Parcel打包React嵌入Widget报ReferenceError: React is not defined
问题根因
报错ReferenceError: React is not defined是因为Parcel构建时默认会把部分依赖识别为外部依赖,不会打包进最终产物,运行时会去全局找对应变量,你的宿主页面没有提前挂载全局React,就会触发报错,不符合单JS无依赖嵌入的需求。
最优解决方案(零外部依赖单JS产物)
1. 修改构建命令
调整package.json里的widget构建脚本,加上--no-external参数,强制Parcel将所有依赖(包括React、ReactDOM)全部内联进最终输出的JS文件,不需要宿主页面提前引入任何依赖:
"scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject", "build:widget": "parcel build src/index.js --no-source-maps --no-external -d widget" }
2. 修正入口文件写法
检查src/index.js入口文件,确保正确引入依赖、做挂载节点判断,避免和宿主页面的元素冲突:
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; // 等DOM加载完成再挂载,避免找不到容器 window.addEventListener('DOMContentLoaded', () => { const container = document.querySelector('#widget-section'); if (!container) return; const root = ReactDOM.createRoot(container); root.render(<App />); });
如果使用React17及以下版本,把挂载逻辑替换为ReactDOM.render(<App />, container)即可。
3. 修正测试HTML的写法
你之前的测试HTML把样式、脚本标签写在了</body>外部,不符合HTML规范,调整为:
<body> <p>Hello World</p> <div id="widget-section"></div> <link href="../widget/index.css" rel="stylesheet" /> <script src="../widget/index.js"></script> </body>
如果想实现真正的单文件引入、不需要额外加载CSS,可以安装对应Parcel插件把样式内联进JS,普通场景下单独引CSS也够用。
不推荐的备选方案
如果不想增加Widget产物体积,可以选择不把React打进bundle,但是需要宿主页面在引入Widget脚本之前,先全局引入对应版本的React、ReactDOM生产版脚本。这种方案会带来版本冲突、依赖顺序错误的问题,不适合需要嵌入任意站点的通用Widget场景。
内容的提问来源于stack exchange,提问作者ololo
相关产品推荐
相关产品推荐

