问题描述
我正在研究 Webpack 5 模块联合功能,但在理解为什么我的代码不起作用时遇到了一些麻烦。 这个想法与标准模块联合示例的做法非常相似:
app1
- 是宿主应用
app2
- 是一个远程将整个应用程序暴露给 app1
(app1
呈现标题和水平线,app2
应呈现在其下方)
app1
和 app2
都将 react
和 react-dom
声明为它们在 weback.config.js
中共享的、单例的、急切的依赖项:
// app1 webpack.config.js
module.exports = {
entry: path.resolve(SRC_DIR,'./index.js');,...
plugins: [
new ModuleFederationPlugin({
name: "app1",remotes: {
app2: `app2@//localhost:2002/remoteEntry.js`,},shared: { react: { singleton: true,eager: true },"react-dom": { singleton: true,eager: true } },}),...
],};
// app2 webpack.config.js
module.exports = {
entry: path.resolve(SRC_DIR,...
plugins: [
new ModuleFederationPlugin({
name: "app2",library: { type: "var",name: "app2" },filename: "remoteEntry.js",exposes: {
"./App": "./src/App",};
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />,document.getElementById("root"));
接下来是 App1 App.js
组件:
import React,{ Suspense } from 'react';
const RemoteApp2 = React.lazy(() => import("app2/App"));
export default function App() {
return (
<div>
<h1>App 1</h1>
<p>Below will be some content</p>
<hr/>
<Suspense fallback={'Loading App 2'}>
<RemoteApp2 />
</Suspense>
</div>
);
}
Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react?1bb3
at Object.__webpack_modules__.<computed> (consumes:133)
at __webpack_require__ (bootstrap:21)
at fn (hot module replacement:61)
at Module../src/index.js (main.bundle.a8d89941f5dd9a37d429.js:239)
at __webpack_require__ (bootstrap:21)
at startup:4
at startup:6
如果我提取所有从 index.js
到 bootstrap.js
并且在 index.js
中的内容
import('./bootstrap');
一切正常。
这让我感到困惑,因为创建者的 official docs 和 blog posts 声明您可以使用 bootstrap.js
方式或将依赖项声明为急切的方式。
如果没有 bootstrap.js
模式它为什么不起作用,我们将不胜感激。
这是我正在构建的完整 GitHub 沙箱的链接:https://github.com/vovkvlad/webpack-module-fedaration-sandbox/tree/master/simple
解决方法
为了使其工作,您需要更改加载远程条目的方式。
- 将
ModuleFederationPlugin
中 app1 的webpack.config.js
配置更新为:
...
new ModuleFederationPlugin({
name: "app1",remoteType: 'var',remotes: {
app2: 'app2',},shared: {
...packageJsonDeps,react: { singleton: true,eager: true,requiredVersion: packageJsonDeps.react },"react-dom": { singleton: true,requiredVersion: packageJsonDeps["react-dom"] }
},}),...
- 将
script
标签添加到您在 app1 中的head
的index.html
:
<script src="http://localhost:2002/remoteEntry.js"></script>
通过进一步的黑客攻击看起来不错!
更新:
只是为了它:我已经使用上述修复为您的沙箱存储库创建了一个 PR: https://github.com/vovkvlad/webpack-module-fedaration-sandbox/pull/2
,只是为了让那些可能错过对初始答案的评论的人清楚:
最初失败的主要原因似乎是在实际运行主机应用程序的代码之后加载了 remoteEntry.js
文件。
bootstrap.js
方法和将直接脚本 <script src="http://localhost:2002/remoteEntry.js"></script>
添加到 <head></head>
标签具有完全相同的结果 - 它们使 remoteEntry.js
被加载和解析 BEFORE 主应用程序的代码。
在引导程序的情况下,顺序是下一个:
-
main_bundle
已加载 - 当主代码被提取到
bootstrap.js
文件时 -remoteEntry.js
被加载 -
bootstrap.js
已加载,实际运行主应用程序
Oleg Vodolazsky 提出的变体事件顺序是下一个:
-
remoteEntry.js
首先加载,因为它被直接添加到html
文件中,并且 webpack 的main_bundle
在 remoteEntry 链接之后被附加到<head></head>
-
main_bundle
已加载并运行应用程序
如果只是尝试在没有引导程序且没有硬编码脚本的情况下运行应用程序,<head></head>
main_bundle
会在 remoteEntry.js
之前加载,并且 main_bundle
尝试实际运行应用程序,它失败并出现错误: