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/**/*"] }
问题原因及解决方法
错误原因
- 重复编译冲突:Webpack中同时配置
babel-loader和ts-loader处理TS/JSX文件,导致同一文件被两次编译,破坏了React的模块导入逻辑,引发useEffect读取null的错误。 - 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, // ...其他配置 } }
验证
- 执行
npm run start,开发环境正常启动,无报错。 - 执行
npm run build,dist目录下同时生成编译后的JS文件和类型声明文件index.d.ts。
内容的提问来源于stack exchange,提问作者Ahmad Echem
相关产品推荐
相关产品推荐

