使用Rollup打包React组件时遭遇表达式错误及构建失败
Rollup构建含JSX的React组件失败的解决方案
问题现象
用Rollup打包包含JSX的React组件时失败,报错指向JSX的Fragment语法<>,提示Expression expected;但去掉JSX的代码可以正常编译。
相关配置与代码
package.json
{ "name": "npm-test-package", "version": "1.0.0", "description": "", "main": "dist/index.js", "type": "module", "scripts": { "build:dev": "rollup -c --environment NODE_ENV:development", "build": "rollup -c --environment NODE_ENV:production" }, "author": "", "license": "ISC", "devDependencies": { "@rollup/plugin-terser": "^0.4.4", "rollup": "^4.13.0" }, "dependencies": { "@rollup/plugin-babel": "^6.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-node-resolve": "^5.2.0" } }
rollup.config.js
import terser from "@rollup/plugin-terser"; import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; import { babel } from "@rollup/plugin-babel"; const devMode = process.env.NODE_ENV === "development"; console.log(`${devMode ? "development" : "production"} mode bundle`); export default [ { input: "src/index.js", output: { file: "dist/index.js", format: "es", sourcemap: devMode ? "inline" : false, plugins: [ terser({ ecma: 2020, mangle: { toplevel: true }, compress: { module: true, toplevel: true, unsafe_arrows: true, drop_console: !devMode, drop_debugger: !devMode, }, output: { quote_style: 1 }, }), ], plugins: [ resolve(), babel({ exclude: "node_modules/**", presets: ["@babel/env", "@babel/preset-react"], }), commonjs(), ], external: ["react", "prop-types"], globals: { react: "React", }, }, }, ];
src/components/MyComponent.js
import React from "react"; const MyComponent = (props) => { const { name } = props; return ( <> <div> <h1>Hello, my name is {name} </h1> </div> </> ); }; export default MyComponent;
报错信息
src/index.js → dist/index.js... [!] RollupError: src/components/MyComponent.js (6:4): Expression expected src/components/MyComponent.js (6:4) 4: const { name } = props; 5: return ( 6: <> ^ 7: <div> 8: <h1>Hello, my name is {name} </h1> RollupError: Expression expected at Object.getRollupError (C:\Users\saura\OneDrive\Desktop\my-awesome-button-alert-component\node_modules\rollup\dist\shared\parseAst.js:282:41) at ParseError.initialise (C:\Users\saura\OneDrive\Desktop\my-awesome-button-alert-component\node_modules\rollup\dist\shared\rollup.js:12586:40) at convertNode (C:\Users\saura\OneDrive\Desktop\my-awesome-button-alert-component\node_modules\rollup\dist\shared\rollup.js:14326:10) at convertProgram (C:\Users\saura\OneDrive\Desktop\my-awesome-button-alert-component\node_modules\rollup\dist\shared\rollup.js:13646:12) at Module.setSource (C:\Users\saura\OneDrive\Desktop\my-awesome-button-alert-component\node_modules\rollup\dist\shared\rollup.js:15463:24) at ModuleLoader.addModuleSource (C:\Users\saura\OneDrive\Desktop\my-awesome-button-alert-component\node_modules\rollup\dist\shared\rollup.js:19758:13)
问题原因
- 插件位置错误:把
babel、resolve、commonjs这些负责源码编译的插件放在了output.plugins里,Rollup的输出插件只处理最终产物,源码编译插件应该放在配置根级别plugins数组中,导致JSX没被转译就被Rollup解析,触发语法错误。 - 依赖缺失&版本问题:缺少
@babel/core和@babel/preset-react的正式依赖,同时使用的rollup-plugin-node-resolve、rollup-plugin-commonjs是旧版,和Rollup 4.x不兼容。 - 配置重复覆盖:
output里写了两个plugins数组,后面的会覆盖前面的,导致terser插件没生效。
修复步骤
1. 修正Rollup配置文件
把编译插件移到根级别plugins,输出配置只保留产物处理插件,同时修复重复plugins的问题:
import terser from "@rollup/plugin-terser"; import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import { babel } from "@rollup/plugin-babel"; const devMode = process.env.NODE_ENV === "development"; console.log(`${devMode ? "development" : "production"} mode bundle`); export default [ { input: "src/index.js", // 根级别plugins,负责转译源码 plugins: [ resolve(), babel({ exclude: "node_modules/**", presets: ["@babel/env", "@babel/preset-react"], babelHelpers: "bundled" // 明确指定babelHelpers模式,避免报错 }), commonjs(), // 只在生产环境启用terser压缩 !devMode && terser({ ecma: 2020, mangle: { toplevel: true }, compress: { module: true, toplevel: true, unsafe_arrows: true, drop_console: true, drop_debugger: true, }, output: { quote_style: 1 }, }) ].filter(Boolean), // 过滤掉dev模式下的terser(false值) output: { file: "dist/index.js", format: "es", sourcemap: devMode ? "inline" : false, external: ["react", "prop-types"], globals: { react: "React", }, }, }, ];
2. 更新依赖包
卸载旧版插件,安装兼容的官方插件和缺失的Babel依赖:
# 卸载旧版非官方插件 npm uninstall rollup-plugin-node-resolve rollup-plugin-commonjs # 安装新版官方插件和Babel核心依赖 npm install --save-dev @rollup/plugin-node-resolve @rollup/plugin-commonjs @babel/core @babel/preset-react @babel/preset-env
3. 调整package.json依赖结构
把Babel相关依赖移到devDependencies(开发编译用,不需要发布到生产):
{ "name": "npm-test-package", "version": "1.0.0", "description": "", "main": "dist/index.js", "type": "module", "scripts": { "build:dev": "rollup -c --environment NODE_ENV:development", "build": "rollup -c --environment NODE_ENV:production" }, "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.24.4", "@babel/preset-env": "^7.24.4", "@babel/preset-react": "^7.24.1", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "rollup": "^4.13.0" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" } }
4. 验证修复
运行构建命令测试:
npm run build
此时JSX会被Babel正确转译为JS代码,Rollup可以正常完成打包。
内容的提问来源于stack exchange,提问作者Saurabh Singh
相关产品推荐
相关产品推荐

