【发布时间】:2020-05-04 05:37:37
【问题描述】:
使用react-app-rewired定制的三个create-react-apps,都使用相同版本的以下包:
"react": "^16.12.0",
"react-app-rewired": "^2.1.5",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2",
"react-scripts": "3.3.0",
应用程序 1,“主”应用程序是其他两个应用程序的一个非常简单的外壳,public/index.html 看起来像这样:
<body>
<div class="main-app"></div>
<div class="sub-app-1"></div>
<div class="sub-app-2"></div>
<script src="sub-app-1/static/js/bundle.js" async></script>
<script src="sub-app-1/static/js/0.chunk.js" async></script>
<script src="sub-app-1/static/js/main.chunk.js" async></script>
<script src="sub-app-2/static/js/bundle.js" async></script>
<script src="sub-app-2/static/js/0.chunk.js" async></script>
<script src="sub-app-2/static/js/main.chunk.js" async></script>
</body>
这很好用,所有三个应用程序都正确呈现。现在需求已经略有变化,sub-app-2 中的唯一一个组件,例如 <PictureFrame /> 需要包含在 sub-app-1 中,我在主项目中创建了一个存根组件,如下所示:
const NullPictureFrame = () => {
return <div></div>;
}
export const PictureFrame = (props: Props) => {
const forceUpdate = useForceUpdate();
useEventListener(window, "PictureFrameComponent.Initialized" as string, () => forceUpdate());
const PictureFrame = window.PictureFrameComponent || NullPictureFrame;
return <PictureFrame />
}
我认为钩子的细节并不重要,但它们在以独立方式运行时确实有效。 sub-app-2 做了类似的事情
window.PictureFrameComponent = () => <PictureFrame />
这在理论上似乎可行,但实际上我最终会遇到以下错误
The above error occurred in the <PictureFrame> component:
in PictureFrame (at src/index.tsx:17)
in Router (at src/index.tsx:16)
in Unknown (at PictureFrames/index.tsx:21)
in PictureFrame (at src/index.tsx:32) <--- in `main-app`
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/docs/error-boundaries.html to learn more about error boundaries. index.js:1
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.
main-app 和 sub-app-2 正在加载 react 的两个不同版本,这在使用挂钩时会导致问题。
我已尝试根据 this github thread 中的建议更新我的 webpack 配置,但似乎 sub-app-2 无法使用此方法找到对 react 的引用。我的main-app/config-overrides.js 看起来像这样:
config.resolve.alias["react"] = path.resolve(__dirname, "./node_modules/react");
config.resolve.alias["react-dom"] = path.resolve(__dirname, "./node_modules/react-dom");
而我的sub-app-1/config-overrides.js 看起来像这样:
config.externals = config.externals || {};
config.externals.react = {
root: "React",
commonjs2: "react",
commonjs: "react",
amd: "react"
};
config.externals["react-dom"] = {
root: "ReactDOM",
commonjs2: "react-dom",
commonjs: "react-dom",
amd: "react-dom"
};
这不会导致错误,而且来自 sub-app-2 的代码没有被 webpack 初始化为 react/react-dom 找不到
编辑 1:澄清
- 有问题的 3 个应用是 3 个完全独立的 (git) 项目,它们都使用相同的依赖项。
- 项目之间唯一允许的“依赖关系”是这种通过使用全局变量、事件、
Window.postMessage或类似的非常松散的耦合。 - 我最初使用
const PictureFrame = window.PictureFrameComponent || NullPictureFrame;的方法效果很好不使用团队一直在使用的钩子,这强化了上面详述的非常丢失依赖项的想法 - 有一种“明显”的方式可以让“react”、“react-dom”和任何依赖它们的东西成为
main-app中externals的一部分并以这种方式加载它们
【问题讨论】:
标签: reactjs webpack react-hooks create-react-app