Есть три create-react-app
, настроенные с использованием react-app-rewired
, оба используют одну и ту же версию следующих пакетов:
"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, приложение "Main" - очень простая оболочка для другие два приложения 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-1
должен быть включен один-единственный компонент sub-app-2
, например <PictureFrame />
, в основном проекте я создал заглушку, например:
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
, и это вызывает проблему при использовании хуков.
Я попытался обновить конфигурацию моего веб-пакета, основываясь на совете в этой ветке github , но это Похоже, что 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;
отлично работает без с использованием хуков, которые команды использовали до сих пор, что укрепило идею очень потерянных зависимостей, подробно описанных выше - Там это «очевидный» способ заставить «реагировать», «реагировать на дом» и все, что зависит от них, как часть
externals
в main-app
и загружать их таким образом