You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Webpack打包React TS组件库时出现useEffect读取null属性错误

React组件包Webpack打包报错:Cannot read properties of null (reading 'useEffect')

我正在开发一个React组件包,使用TypeScript开发,未通过CRA创建项目,React和React-Dom均为最新版本。使用Webpack打包后出现如下错误:

react.development.js:1634 Uncaught TypeError: Cannot read properties of null (reading 'useEffect')
    at Object.useEffect (react.development.js:1634:1)
    at l (index.js:1:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at beginWork$1 (react-dom.development.js:27426:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
    at renderRootSync (react-dom.development.js:26434:1)
    at recoverFromConcurrentError (react-dom.development.js:25850:1)

移除Webpack配置中的ts-loader后程序可正常运行,但无法生成类型声明文件。以下是相关配置文件:

Webpack配置

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const nodeExternals = require('webpack-node-externals');
module.exports = {
  entry: path.resolve(__dirname, "./src/index.tsx"),
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
    extensionAlias: {
      ".js": [".js", ".ts"],
      ".cjs": [".cjs", ".cts"],
      ".mjs": [".mjs", ".mts"]
     },
  },
  module: {
    rules: [
      {
        test: /\.(ts|js)x?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "babel-loader",
          },
        ],
      },
      { test: /\.([cm]?ts|tsx)$/, loader: "ts-loader" },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
        type: "asset/resource",
      },
      {
        test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
        type: "asset/inline",
      },
    ],
  },
  externals: [nodeExternals()],
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "index.js",
    libraryTarget: "commonjs",
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "./src/index.html"),
    }),
  ],
  stats: "errors-only",
};

Package.json内容

{
  "name": "my-app",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack serve --config webpack.config.js --open",
    "build": "rm -rf ./dist && webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "peerDependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.12",
    "@babel/plugin-transform-runtime": "^7.19.6",
    "@babel/preset-env": "^7.20.2",
    "@babel/preset-react": "^7.18.6",
    "@babel/preset-typescript": "^7.18.6",
    "@types/react": "^18.0.26",
    "@types/react-dom": "^18.0.10",
    "babel-loader": "^9.1.2",
    "html-webpack-plugin": "^5.5.0",
    "ts-loader": "^9.4.2",
    "typescript": "^4.9.4",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1",
    "webpack-node-externals": "^3.0.0"
  }
}

TS Config内容

{
    "compilerOptions": {
      "target": "ES5",
      "module": "ESNext",
      "moduleResolution": "node",
      "declaration": true,
      "outDir": "dist",
      "lib": [
        "DOM",
        "ESNext"
      ],
      "jsx": "react-jsx",
      "noEmit": false,
      "isolatedModules": true,
      "esModuleInterop": true,
      "strict": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true,
      "resolveJsonModule": true,
      "sourceMap": true
    },
    "include": ["src/**/*"]
  }

问题原因及解决方法

错误原因

  1. 重复编译冲突:Webpack中同时配置babel-loader和ts-loader处理TS/JSX文件,导致同一文件被两次编译,破坏了React的模块导入逻辑,引发useEffect读取null的错误。
  2. externals配置不区分环境:webpack-node-externals会排除所有node_modules依赖,但开发环境运行组件时,React需要被打包进浏览器bundle,该配置导致React未被正确加载。

解决步骤

1. 合并编译规则,移除重复的ts-loader

利用已配置的@babel/preset-typescript,让babel-loader单独处理TS/JSX文件,避免重复编译:

module: {
  rules: [
    {
      test: /\.(ts|js)x?$/,
      exclude: /node_modules/,
      use: ["babel-loader"],
    },
    // 移除单独的ts-loader规则
    {
      test: /\.css$/,
      use: ["style-loader", "css-loader"],
    },
    {
      test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
      type: "asset/resource",
    },
    {
      test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
      type: "asset/inline",
    },
  ],
},

2. 区分环境配置externals

生产环境打包组件时,将React设为外部依赖(依赖peerDependencies);开发环境运行demo时,打包React到bundle:

const isProduction = process.env.NODE_ENV === 'production';

module.exports = {
  // ...其他配置
  externals: isProduction ? [nodeExternals()] : [],
  // ...其他配置
}

3. 单独生成类型声明文件

在package.json的scripts中添加TypeScript单独生成声明的命令:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "start": "webpack serve --config webpack.config.js --open",
  "build": "rm -rf ./dist && webpack --mode production && tsc --emitDeclarationOnly"
}

4. 调整tsconfig.json配置

添加emitDeclarationOnly确保只生成类型文件,兼容isolatedModules:

{
  "compilerOptions": {
    // ...其他配置
    "isolatedModules": true,
    "declaration": true,
    "emitDeclarationOnly": true,
    // ...其他配置
  }
}

验证

  1. 执行npm run start,开发环境正常启动,无报错。
  2. 执行npm run build,dist目录下同时生成编译后的JS文件和类型声明文件index.d.ts。

内容的提问来源于stack exchange,提问作者Ahmad Echem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:40:32