错误:未找到模块:无法解析 ‘@sendgrid/helpers/classes’ 中的 ‘fs’ 和 ‘path’

huangapple go评论83阅读模式
英文:

Error: Module not found: Can't resolve 'fs' and 'path' in '@sendgrid/helpers/classes'

问题

  1. SendGrid is typically used in server-side applications, not in browser-based React applications. This error occurs because the 'fs' and 'path' modules are part of the Node.js runtime, which is not available in the browser environment.

  2. To make SendGrid work in your React application, you should move the code that sends emails to a server-side component, such as a Node.js server. You can create an API endpoint on your server that your React application can call when the contact form is submitted. This server-side component can then use the SendGrid module to send emails without encountering the 'fs' and 'path' module errors.

  3. Alternative solutions to send emails from a contact form in a React application include:

    • Using a serverless function: You can use serverless functions like AWS Lambda or Netlify Functions to handle email sending. These functions can be triggered by an API call from your React application.

    • Utilizing a backend service: Consider using a backend-as-a-service (BaaS) or a serverless framework that includes email sending capabilities, such as Firebase Cloud Functions or AWS SES (Simple Email Service).

    • Implementing a custom server: You can create a custom server using Node.js or another backend technology to handle email sending. This approach offers flexibility and control over the email sending process.

Remember that when sending emails, it's important to handle sensitive data like API keys securely and avoid exposing them in your frontend code to protect your application's security.

英文:

I'm trying to use the SendGrid module in my React application to send an email using a contact form. However, when I run npm start, I encounter the following error:

Failed to compile.
Module not found: Error: Can't resolve 'fs' in '.../node_modules/@sendgrid/helpers/classes'

The error message suggests that the 'fs' and 'path' modules cannot be resolved in the @sendgrid/helpers/classes/attachment.js file.

I also receive the warning:

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

Here is my project structure:
card.tsx (React component for the contact form):

import React, { useState, useEffect, useRef } from "react";
import cardcss from "./Card.module.css";

interface CardProps {
  imageUrl: string;
  title: string;
  body: string;
  onSubmitForm: (contactData: {
    Name: string;
    Email: string;
    Message: string;
  }) => void;
}

function Card(props: CardProps) {
  const [message, setMessage] = useState("");
  const messageInputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    if (messageInputRef.current) {
      messageInputRef.current.focus();
      messageInputRef.current.setSelectionRange(0, 0);

      // Delay setting the cursor position
      setTimeout(() => {
        messageInputRef.current?.setSelectionRange(0, 0);
      }, 0);
    }
  }, []);

  const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => {
    event.target.setSelectionRange(0, 0);
  };

  function ContactForm() {
    const nameInputRef = useRef<HTMLInputElement>(null);
    const emailInputRef = useRef<HTMLInputElement>(null);
    const messageInputRef = useRef<HTMLInputElement>(null);
    const submitRef = useRef<HTMLButtonElement>(null);

    function submitHandler(event: React.FormEvent<HTMLFormElement>) {
      event.preventDefault();

      if (
        nameInputRef.current &&
        emailInputRef.current &&
        messageInputRef.current
      ) {
        const nameInput = nameInputRef.current.value;
        const emailInput = emailInputRef.current.value;
        const messageInput = messageInputRef.current.value;

        const contactData = {
          Name: nameInput,
          Email: emailInput,
          Message: messageInput,
        };

        if (submitRef.current) {
          const submittedButton = submitRef.current.value;

          const contactDataWithButton = {
            ...contactData,
            submitbutton: submittedButton,
          };

          // Do something with contactDataWithButton
          props.onSubmitForm(contactData);
        }
      }
    }


    return (
      <div className={cardcss.cardcontainer}>
        <div className={cardcss.imagecontainer}>
          <img src={props.imageUrl} alt="" />
        </div>

        <div className={cardcss.cardtitle}>
          <h3>{props.title}</h3>
        </div>

        <div className={cardcss.cardbody}>
          <p>{props.body}</p>

          <form onSubmit={submitHandler}>
            <div>
              <label className={cardcss.namelabel} htmlFor="name">
                Name:
              </label>
              <input
                className={cardcss.nameinput}
                type="text"
                id="name"
                name="name"
                ref={nameInputRef}
              />
            </div>

            <div className={cardcss.emailcontainer}>
              <label className={cardcss.emaillabel} htmlFor="email">
                Email:
              </label>
              <input
                className={cardcss.emailinput}
                type="text"
                id="email"
                name="email"
                ref={emailInputRef}
              />
            </div>

            <div className={cardcss.messagecontainer}>
              <label className={cardcss.messagelabel} htmlFor="message">
                Message:
              </label>
              <input
                ref={messageInputRef}
                className={cardcss.messageinput}
                type="text"
                id="message"
                name="message"
                value={message}
                onChange={(e) => setMessage(e.target.value)}
                onFocus={handleFocus}
              />

              <button className={cardcss.sendbutton} ref={submitRef}>
                Send
              </button>
            </div>
          </form>
        </div>
      </div>
    );
  }

  return <ContactForm />;
}

export default Card;

contact.tsx(React component that uses the Card component):

import React, { useRef } from "react";
import contactcss from "./Contact.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Card from "../../components/ui/Card";
import {
  faInstagram,
  faFacebook,
  faLinkedin,
  faDiscord,
} from "@fortawesome/free-brands-svg-icons";
import emaillogo from "../../resources/email-logo.png";
import { setApiKey, send } from "@sendgrid/mail";

const Contact: React.FC = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleClick = () => {
    if (inputRef.current) {
      inputRef.current.focus();
      inputRef.current.setSelectionRange(0, 0);
    }
  };

  setApiKey(
    "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"
  ); 

  function submitFormHandler(contactData: {
    Name: string;
    Email: string;
    Message: string;
  }) {
    const { Name, Email, Message } = contactData;

    const msg = {
      to: "paristiffany12@gmail.com",
      from: Email,
      subject: "GDSC Contact Form - New Message",
      text: `Message from: ${Name}\nMessage: ${Message}`,
      html: `<p>Message from: ${Name}</p><p>Message: ${Message}</p>`,
    };

    send(msg)
      .then(() => {
        console.log("Email sent successfully");
      })
      .catch((error) => {
        console.error(error.toString());
      });
  }

  return (
    <div>
      <div>
        <div className={contactcss.background}>
          <img
            className={contactcss.emaillogo}
            src={emaillogo}
            alt="Contact Us"
          />
          <div className={contactcss.contact}>Contact Us</div>
        </div>
      </div>

      <Card
        title="We're keen to hear from you!"
        imageUrl="https://images.app.goo.gl/D6m6hHMnP1gjsKKV7"
        body=""
        onSubmitForm={submitFormHandler}
      />

      <div className={contactcss.whitebackground}>
        <div className={contactcss.socials}>
          <h1>Follow Our Socials</h1>
          <p className={contactcss.socialmedia}>
            Stay connected with GDSC USYD by following us on our social media
            channels:
          </p>
          <div>
            <a href="https://www.instagram.com/gdscusyd/">
              <FontAwesomeIcon
                className={contactcss.instagram}
                icon={faInstagram}
              />
            </a>

            <a href="https://www.facebook.com/gdsc.usyd">
              <FontAwesomeIcon
                className={contactcss.facebook}
                icon={faFacebook}
              />
            </a>

            <a href="https://discord.com/channels/872033047652990986/872033047652990989">
              <FontAwesomeIcon
                className={contactcss.discord}
                icon={faDiscord}
              />
            </a>

            <a href="https://www.linkedin.com/company/gdsc-usyd/">
              <FontAwesomeIcon
                className={contactcss.linkedin}
                icon={faLinkedin}
              />
            </a>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Contact;

indexfirebase.js (Node.js file to handle sending emails):

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var express_1 = require("express");
var mail_1 = require("@sendgrid/mail");
var path_browserify_1 = require("path-browserify");
// Set up SendGrid API key
mail_1.default.setApiKey("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");
// Create Express app
var app = (0, express_1.default)();
// Middleware to parse JSON requests
app.use(express_1.default.json());
// Route to handle sending emails
app.post("/send-email", function (req, res) {
    var _a = req.body, Name = _a.Name, Email = _a.Email, Message = _a.Message, submitbutton = _a.submitbutton;
    var msg = {
        to: "paristiffany12@gmail.com",
        from: "gdscusyd@gmail.com",
        subject: "Example Subject",
        text: "Name: ".concat(Name, "\nEmail: ").concat(Email, "\nMessage: ").concat(Message, "\nSubmit Button: ").concat(submitbutton),
        html: "<p>Name: ".concat(Name, "</p><p>Email: ").concat(Email, "</p><p>Message: ").concat(Message, "</p><p>Submit Button: ").concat(submitbutton, "</p>"),
    };
    mail_1.default
        .send(msg)
        .then(function () {
        res.status(200).json({ message: "Email sent successfully" });
    })
        .catch(function (error) {
        console.error(error.toString());
        res.status(500).json({ error: "Failed to send email" });
    });
});
// Set up fallback for path module
path_browserify_1.resolve.fallback = { path: path_browserify_1.require.resolve("path-browserify") };
// Start the server
app.listen(3000, function () {
    console.log("Server started on port 3000");
});

I believe this error is occurring because the fs and path modules are part of the Node.js environment and are not available in a browser environment.

My questions are:

  1. Can I use the SendGrid module in a browser-based React application?
  2. Is it possible to fix this error and make the SendGrid module work in my React application?
  3. If it's not possible, what alternatives can I use to send emails from a contact form in a React application?

I appreciate any help or guidance to resolve this issue. Thank you in advance!

答案1

得分: 1

你的假设是正确的,不可能在客户端上运行Node.js模块。出于安全原因,这也不建议,因为它会将你的API密钥暴露给世界。

相反,你需要在服务器上实现所有与SendGrid相关的代码(如express、Next.js或类似的框架)。

英文:

You assumption is right, it is not possible to run nodejs modules on the client. And for security reasons this is also not recommended as it'll expose your API key to the world.

Instead, you need to implement all SendGrid-related code on the server (like express, Next.js or similar)

huangapple
  • 本文由 发表于 2023年6月22日 09:14:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76528077.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定