React Module Federation - Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react

React Module Federation - Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react

我正在尝试反应模块联合。我使用 create-react-app 命令创建了两个反应应用程序(modulefederation1,modulefederation2)。当我 运行 应用程序时出现 'Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react' 错误。

节点版本: v16.14.2

下面是我的代码。

modulefederation1:

Package.json:

{
  "name": "modulefederation1",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.2.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.1",
    "@types/node": "^16.11.36",
    "@types/react": "^18.0.9",
    "@types/react-dom": "^18.0.4",
    "html-webpack-plugin": "^5.5.0",
    "react": "^18.1.0",
    "react-dom": "^18.1.0",
    "react-scripts": "5.0.1",
    "serve": "^13.0.2",
    "ts-loader": "^9.3.0",
    "typescript": "^4.6.4",
    "web-vitals": "^2.1.4",
    "webpack": "^5.72.1",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.9.0"
  },
  "scripts": {
    "start": "webpack serve --open",
    "build": "webpack --config webpack.prod.js",
    "serve": "serve dist -p 3002",
    "clean": "rm -rf dist"
},
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // only add this if you don't have yet
const { ModuleFederationPlugin } = webpack.container;
const deps = require('./package.json').dependencies;

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';
  console.log({ isProduction });
  return {
    entry: './src/index.tsx',
    mode: process.env.NODE_ENV || 'development',
    devServer: {
      port: 3000,
      open: true,
    },
    resolve: {
      extensions: ['.ts', '.tsx', '.js'],
    },
    module: {
      rules: [
        {
          test: /\.(js|jsx|tsx|ts)$/,
          loader: 'ts-loader',
          exclude: /node_modules/,
        },
      ],
    },

    plugins: [
      new ModuleFederationPlugin({
        name: 'container',
        remotes: {
          app1: 'app1@http://localhost:3001/remoteEntry.js'
        },
        shared: {
          ...deps,
          react: { singleton: true, eager: true, requiredVersion: deps.react },
          'react-dom': {
            singleton: true,
            eager: true,
            requiredVersion: deps['react-dom'],
          },
        },
      }),
      new HtmlWebpackPlugin({
        template: './public/index.html',
      }),
    ],
  };
};

public/index.html:

<html>
  <head>
    <title>CONTAINER</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

src/index.tsx:

import './bootstrap';

src/bootstrap.tsx:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

src/App.tsx:

import React from 'react';

const ModuleFederationTwo = React.lazy(() => import('app1/ModuleFederationTwo'));

function App() {
  return (
    <div >
     Container application
    </div>
  );
}

export default App;

modulefederation2:

Pacakge.json 文件与 modulefederation1 相同,除了 "name": "modulefederation2"

webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
const path = require('path');
const deps = require('./package.json').dependencies;

module.exports = {
  entry: './src/index.tsx',
  mode: 'development',
  devServer: {
    port: 3001,
    open: true,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx|tsx|ts)$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'app1',
      filename: 'remoteEntry.js',
      exposes: {
        // expose each component
        './ModuleFederationTwo': './src/App',
      },
      shared: {
        ...deps,
        react: { singleton: true, eager: true, requiredVersion: deps.react },
        'react-dom': {
          singleton: true,
          eager: true,
          requiredVersion: deps['react-dom'],
        },
      },
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

src/index.tsx 和 src/bootstrap.tsx 文件与 modulefederation1

相同

src/App.tsx:

import React from 'react';
import './App.css';

function App() {
  return (
    <div className="App">
      MFE application One
    </div>
  );
}

export default App;

我运行 modulefederation1, modulefederation2 使用yarn start.

我收到 main.js:1312 未捕获错误:共享模块不可用于急切消费:当我 运行 modulefederation1 时出现 webpack/sharing/consume/default/react/react 错误申请。

当我浏览时,每个人都说索引代码应该移动到 bootstrap,我已经这样做了。我还有其他解决方案吗?

网络:

我能够通过更改以下代码使上面的代码工作。

modulefederation1:

public/index.html:- 添加脚本标签 <script src="http://localhost:3001/remoteEntry.js"></script>

<html>
  <head>
    <script src="http://localhost:3001/remoteEntry.js"></script>
    <title>CONTAINER</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

webpack.config.js: 更改遥控器 app1 值

remotes: {
          app1: 'app1'
        },