Babel/Webpack配置异常:构建测试报错及.env适配方案咨询
解决Babel+Webpack构建错误与Jest测试模块语法问题
错误原因分析
1. 构建错误:Error: Plugin/Preset files are not allowed to export objects, only functions.
- 项目同时安装了Babel 7核心包(
@babel/core、@babel/preset-env等)和Babel 6时代的旧预设包(babel-preset-es2015、babel-preset-react),旧包导出格式与Babel 7不兼容。 - Webpack配置中重复定义Babel的presets/plugins,与根目录
babel.config.json的配置冲突,导致加载了错误版本的预设。
2. 测试错误:SyntaxError: Cannot use import statement outside a module
- Jest默认不支持直接解析ES模块语法,需通过Babel转译测试代码与源码。
- 测试环境未正确加载Babel配置,且未处理
.env文件的环境变量注入。
分步解决方案
1. 清理冲突依赖
移除Babel 6的旧预设包,保留Babel 7官方预设:
npm uninstall babel-preset-es2015 babel-preset-react
2. 简化Webpack的Babel配置
删除Webpack中重复的Babel选项,让babel-loader自动读取babel.config.json的配置,避免冲突。修改webpack.config.js的module.rules和target:
module: { rules: [ // 合并js与jsx规则,无需分开配置 { test: /\.(js|jsx)$/, exclude: /node_modules/, use: 'babel-loader' }, ] }, target: 'web', // 前端项目需设置为web,原node是后端项目用的
3. 优化Babel配置
调整babel.config.json,确保测试环境包含React预设(否则测试React组件会报错):
{ "presets": [ "@babel/preset-env", [ "@babel/preset-react", { "runtime": "automatic" } ], "@babel/preset-typescript" ], "plugins": [ [ "@babel/plugin-transform-runtime", { "useESModules": true, "regenerator": false } ] ], "env": { "test": { "presets": [ ["@babel/preset-env", { "targets": { "node": "current" } }], "@babel/preset-react" ] } } }
4. 配置Jest支持ES模块与.env文件
在package.json中添加Jest配置:
"jest": { "transform": { "^.+\\.(js|jsx|ts|tsx)$": "babel-jest" }, "moduleNameMapper": { "\\.(css|scss|sass)$": "<rootDir>/__mocks__/styleMock.js", "\\.(png|jpg|jpeg|gif|svg)$": "<rootDir>/__mocks__/fileMock.js" }, "setupFiles": [ "dotenv/config" ], "testEnvironment": "jsdom" }
创建__mocks__文件夹及对应mock文件:
__mocks__/styleMock.js:
module.exports = {};
__mocks__/fileMock.js:
module.exports = "test-file-stub";
5. 统一.env加载逻辑
- Webpack通过
dotenv-webpack插件加载.env,保持现有配置即可。 - 测试环境通过Jest的
setupFiles中的dotenv/config自动加载.env。
修改后的完整配置
webpack.config.js
const path = require('path') const Dotenv = require('dotenv-webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { devtool: "source-map", mode: process.env.NODE_ENV, entry: './src/index.js', output: { path: path.resolve(__dirname, './build'), filename: 'bundle.js', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: 'babel-loader' }, ] }, resolve: { fallback: { fs: false, }, alias: { config$: './configs/app-config.js', react: './vendor/react-master', }, extensions: ['.js', '.jsx', '.ts', '.tsx'], modules: [ 'node_modules', 'bower_components', 'shared', '/shared/vendor/modules', ], }, target: 'web', plugins: [ new Dotenv({ path: './.env', safe: true, allowEmptyValues: true, systemvars: true, silent: true, defaults: false, }), new HtmlWebpackPlugin({ inject: true, template: path.resolve('./public/index.html') }), ] }
babel.config.json
{ "presets": [ "@babel/preset-env", [ "@babel/preset-react", { "runtime": "automatic" } ], "@babel/preset-typescript" ], "plugins": [ [ "@babel/plugin-transform-runtime", { "useESModules": true, "regenerator": false } ] ], "env": { "test": { "presets": [ ["@babel/preset-env", { "targets": { "node": "current" } }], "@babel/preset-react" ] } } }
package.json(关键修改部分)
{ "scripts": { "start": "env-cmd -f .env webpack-dev-server --open", "build": "cross-env NODE_ENV=production env-cmd -f .env webpack", "test": "cross-env NODE_ENV=test jest", "eject": "react-scripts eject" }, "dependencies": { "@jest/globals": "^29.4.2", "@react-three/drei": "^9.57.3", "@react-three/fiber": "^8.12.0", "@reduxjs/toolkit": "^1.9.2", "@testing-library/user-event": "^14.4.3", "@types/node": "^18.11.19", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", "@types/react-redux": "^7.1.25", "autoprefixer": "10.4.5", "axios": "^1.3.2", "dotenv": "^16.0.3", "env-cmd": "^10.1.0", "eslint-config-ts-react-important-stuff": "^3.0.0", "fs": "^0.0.1-security", "html-webpack-plugin": "^5.5.0", "immer": "^9.0.19", "maplibre-gl": "^2.4.0", "node-sass": "^7.0.3", "os": "^0.1.2", "path": "^0.12.7", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^7.0.0", "react-scripts": "^5.0.1", "redux": "^4.2.1", "redux-form": "^8.3.9", "redux-logger": "^3.0.6", "redux-mock-store": "^1.5.4", "redux-thunk": "^2.4.2", "sass": "^1.58.0", "three": "^0.149.0", "typescript": "^4.9.5", "web-vitals": "^3.1.1", "webpack": "^5.75.0", "webpack-cli": "^5.0.1", "webpack-dev-server": "^4.7.3" }, "devDependencies": { "@babel/core": "^7.20.12", "@babel/eslint-parser": "^7.19.1", "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", "@cfaester/enzyme-adapter-react-18": "^0.6.0", "@svgr/webpack": "^6.5.1", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@types/jest": "^27.5.2", "@types/redux-logger": "^3.0.9", "@types/testing-library__jest-dom": "^5.14.5", "babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-preset-jest": "^29.4.2", "cross-env": "^7.0.3", "dotenv-webpack": "^8.0.1", "enzyme": "^3.11.0", "jest": "^27.5.1", "jest-cli": "^27.5.1", "react-test-renderer": "^18.2.0", "util": "^0.12.5" }, "jest": { "transform": { "^.+\\.(js|jsx|ts|tsx)$": "babel-jest" }, "moduleNameMapper": { "\\.(css|scss|sass)$": "<rootDir>/__mocks__/styleMock.js", "\\.(png|jpg|jpeg|gif|svg)$": "<rootDir>/__mocks__/fileMock.js" }, "setupFiles": [ "dotenv/config" ], "testEnvironment": "jsdom" } }
内容的提问来源于stack exchange,提问作者Max KievSky
相关产品推荐
相关产品推荐

