Webpack (in prod) bundles give error: TypeError: (0 , tm.useEffect) is not a function...why?

Webpack (in prod) bundles give error: TypeError: (0 , tm.useEffect) is not a function...why?

我的 React 应用程序使用 Webpack + Babel。当我在开发中编译时,一切都运行良好。

当我为生产打包(“npm 运行 build”)并在 prod 中上传打包时,控制台中出现错误:

为什么?我发现了一个类似的问题,但没有找到答案:

这是我的 webpack.prod.js 配置:

const TerserPlugin = require("terser-webpack-plugin");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { ProvidePlugin, web } = require("webpack");
const cleanPlugin = require("clean-webpack-plugin");

module.exports = {
  mode: "production",

  devtool: "source-map",
  entry: ["regenerator-runtime/runtime.js", "./src/index.js"],

  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "index_bundle.js",

  },

  module: {
    rules: [
      {
        test: /\.(jsx|js)$/,
        exclude: /[\/]node_modules[\/]/,

        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.svg$/,
        use: {
          loader: "svg-url-loader",
        },
      },
    ],
  },

  resolve: {
    alias: { react: path.resolve("./node_modules/react") },
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "src/index.html",
      title: "Production",
    }),
    //no need to import react in every module
    new ProvidePlugin({
      React: "react",
    }),
    //erase "dist" bundle before every "npm run build"
    new cleanPlugin.CleanWebpackPlugin(),
  ],

  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: true,
      }),
    ],
  },
  
};


Package.json:

{
  "name": "timerfrontend",
  "version": "1.0.0",
  "main": "index.js",
  "babel": {
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react"
    ]
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack serve --config webpack.config.js",
    "create": "webpack -w",
    "build": "webpack --config webpack.prod.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.16.5",
    "@babel/preset-env": "^7.16.5",
    "@babel/preset-react": "^7.16.5",
    "babel-loader": "^8.2.3",
    "css-loader": "^6.5.1",
    "css-minimizer-webpack-plugin": "^3.3.1",
    "html-webpack-plugin": "^5.3.1",
    "style-loader": "^3.3.1",
    "webpack": "^5.65.0",
    "webpack-cli": "^4.9.1",
    "webpack-dev-server": "^4.7.1"
  },
  "dependencies": {
    "@apollo/client": "^3.5.6",
    "@apollo/link-context": "^2.0.0-beta.3",
    "@apollo/react-hooks": "^4.0.0",
    "@auth0/auth0-react": "^1.8.0",
    "apollo-cache-inmemory": "^1.6.6",
    "apollo-client": "^2.6.10",
    "apollo-link-http": "^1.5.17",
    "bootstrap": "^5.0.1",
    "clean-webpack-plugin": "^4.0.0",
    "dayjs": "^1.10.5",
    "npm-force-resolutions": "^0.0.10",
    "prop-types": "^15.8.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^6.2.1",
    "regenerator-runtime": "^0.13.9",
    "svg-url-loader": "^7.1.1",
    "terser-webpack-plugin": "^5.3.0",
    "webpack-merge": "^5.8.0"
  },
  "peerDependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "description": "",
  "resolutions": {
    "react": "17.0.2",
    "graphql": "16.1.0"
  }
}

控制台错误指向该索引bundle.js:2 代码:

错误是指我项目中的这个反应组件:

import React, { useEffect } from "react";
import { useMutation } from "@apollo/client";
import { NEW_SESSION, newSessionVariables } from "../../graphql/newSession.js";
import { GET_TOTAL_SESSIONS_TODAY } from "../../graphql/getSessions";
import dayjs from "dayjs";

const sessionCreateDate = dayjs().format("M-D-YYYY");

const TimerAtZero = ({ timerState, toggle, user = { name: "" } }) => {
  const [createSession, { data, loading, error }] = useMutation(NEW_SESSION, {
    refetchQueries: [
      { query: GET_TOTAL_SESSIONS_TODAY, variables: { sessionCreateDate, userName: user.name } },
    ],
  });
  const { endSession } = toggle;

  React.useEffect(() => {
    if (timerState.seconds === 0 && timerState.minutes === 0) {
      endSession();
      createSession(newSessionVariables(user.name, timerState));
    }
  }, [timerState.seconds, timerState.minutes]);

  if (loading) return <div>Submitting...</div>;
  if (error) return <div>{error.message}</div>;
  return null;
};

export default TimerAtZero;


将别名指向节点模块是错误的。只需删除您的 resolve 条目,一切都会 运行 正常。

const TerserPlugin = require("terser-webpack-plugin");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { ProvidePlugin, web } = require("webpack");
const cleanPlugin = require("clean-webpack-plugin");

module.exports = {
  mode: "production",

  devtool: "source-map",
  entry: ["regenerator-runtime/runtime.js", "./src/index.js"],

  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "index_bundle.js",

  },

  module: {
    rules: [
      {
        test: /\.(jsx|js)$/,
        exclude: /[\/]node_modules[\/]/,

        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.svg$/,
        use: {
          loader: "svg-url-loader",
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "src/index.html",
      title: "Production",
    }),
    new ProvidePlugin({
      React: "react",
    }),
    new cleanPlugin.CleanWebpackPlugin(),
  ],

  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: true,
      }),
    ],
  },
  
};

如果仍然崩溃,请删除 ProvidePlugin 并在受影响的文件中手动导入 React。

首先,不要使用缩小版本来查找错误,它通常以一种没有意义的奇怪方式显示问题。在 webpack 中使用 optimization.minimize = false 可以帮助解决这个问题。

使用webpack时需要注意的一些情况ProvidePlugin.

您用于 linting、类型检查、分析器等的工具也应该配置为检测全局导入,这在其他配置文件中需要更多的工作和维护。

例如 eslint 你可以这样做:

{
    "globals": {
        "ReactDOM": true
    }
}

如果有一天你选择改变你的捆绑器,那么如果另一个捆绑器不支持像 ProvidePlugin.

这样的东西,你将很难过

而且新开发人员如果不知道 ProvidePlugin,一开始可能会感到困惑。但是每个人都知道 import!

考虑到这些问题,最终取决于您和您的项目是否值得使用ProvidePlugin

如果您使用 ProvidePlugin 只是因为每次都输入 import react 很困难,那么您需要在编辑器中使用代码片段。例如,在 VSCode 中有一个 plugin 有这种片段。或者,您可以根据需要创建自己的代码段。