Webpack 模块联合不适用于急切的共享库

问题描述

我正在研究 Webpack 5 模块联合功能,但在理解为什么我的代码不起作用时遇到了一些麻烦。 这个想法与标准模块联合示例的做法非常相似:

app1 - 是宿主应用 app2 - 是一个远程将整个应用程序暴露给 app1

app1 呈现标题和水平线,app2 应呈现在其下方)

app1app2 都将 reactreact-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",};

在 App1 index.js 我有一个代码

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.jsbootstrap.js 并且在 index.js 中的内容

import('./bootstrap');

一切正常。

这让我感到困惑,因为创建者的 official docsblog posts 声明您可以使用 bootstrap.js 方式或将依赖项声明为急切的方式。

如果没有 bootstrap.js 模式它为什么不起作用,我们将不胜感激。

这是我正在构建的完整 GitHub 沙箱的链接https://github.com/vovkvlad/webpack-module-fedaration-sandbox/tree/master/simple

解决方法

为了使其工作,您需要更改加载远程条目的方式。

  1. 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"] }
    },}),...
  1. script 标签添加到您在 app1 中的 headindex.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 主应用程序的代码。

在引导程序的情况下,顺序是下一个:

  1. main_bundle 已加载
  2. 当主代码被提取到 bootstrap.js 文件时 - remoteEntry.js 被加载
  3. bootstrap.js 已加载,实际运行主应用程序

enter image description here

Oleg Vodolazsky 提出的变体事件顺序是下一个:

  1. remoteEntry.js 首先加载,因为它被直接添加到 html 文件中,并且 webpack 的 main_bundle 在 remoteEntry 链接之后被附加到 <head></head>
  2. main_bundle 已加载并运行应用程序

enter image description here

如果只是尝试在没有引导程序且没有硬编码脚本的情况下运行应用程序,<head></head> main_bundle 会在 remoteEntry.js 之前加载,并且 main_bundle 尝试实际运行应用程序,它失败并出现错误:

enter image description here

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...