Webpack5 模块联邦的使用

发布于 2022-09-12 10:51:16 字数 5089 浏览 201 评论 0

WHAT(Module Federation 是什么?)Module Federation [ˌfedəˈreɪʃn] 使 JavaScript 应用得以在客户端或服务器上动态运行另一个 bundle 的代码。这其中的关键点是:动态,包含两个含义:

  1. 按需,可以把一个包拆开来加载其中一部分;
  2. 运行时,跑在浏览器而非 node 编译时;

另一个 bundle 的代码,之前应用之间做共享是在文件级或 npm 包级 export 成员,现在可以在应用级 export 成员属性。

Module Federation 里有两个主要概念 host 和 remote。每个项目可以是 host 也可以是 remote,也可以两个都是。

配置 remote

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  mode: "development",
  entry: "./src/index.js",
  cache: {
    type: "filesystem",
    cacheDirectory: path.resolve(__dirname, "node_modules/.cache/webpack"),
  },
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "http://localhost:8000/",
  },
  devServer: {
    port: 8000,
  },
  optimization: {
    usedExports: true,
  },
  devtool: false,
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-react"],
            },
          },
        ],
        exclude: /node_modules/,
      },
      {
        test: /\.png$/,
        type: "asset/resource",
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
    new ModuleFederationPlugin({ // 这里是重点部分
      filename: "remoteEntry.js",
      name: "remote",
      exposes: {
        "./NewsList": "./src/NewsList",
      },
    }),
  ],
};

src/index.js

import("./bootstrap");

src/bootstrap.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));

src/App.js

import React from "react";
import NewsList from './NewsList';
const App = () => (
  <div>
    <h2>本地组件NewsList</h2>
    <NewsList />
  </div>
);

export default App;

src/NewsList.js 这个组件导出给别人使用,在 webpack 配置中可以看到。

import React from "react";
export default ()=>(
    <div>新闻列表</div>
)

配置 host

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  mode: "development",
  entry: "./src/index.js",
  cache: {
    type: "filesystem",
    cacheDirectory: path.resolve(__dirname, "node_modules/.cache/webpack"),
  },
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "http://localhost:9000/",
  },
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 9000,
  },
  optimization: {
    usedExports: true,
  },
  devtool: false,
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-react"],
            },
          },
        ],
        exclude: /node_modules/,
      },
      {
        test: /\.png$/,
        type: "asset/resource",
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
    new ModuleFederationPlugin({ // 这里是重点部分
      filename: "remoteEntry.js",
      name: "host",
      remotes: {
        remote: "remote@http://localhost:8000/remoteEntry.js"
      }
    })
  ],
};

src/index.js

import("./bootstrap");

src/bootstrap.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));

src/App.js 中导入了之前别人写好的 NewsList 组件,在 webpack 配置中可以看到。

import React from "react";
const RemoteNewsList = React.lazy(() => import("remote/NewsList"));

const App = () => (
  <div>
    <h2 >远程组件NewsList</h2>
    <React.Suspense fallback="Loading NewsList">
      <RemoteNewsList />
    </React.Suspense>
  </div>
);
export default App;

A 应用可以引用 B 整个应用,也可以应用 B 的页面和组件。这样一来,灵活性就非常大了。

配置参数

字段类型含义
namestring必传值,即输出的模块名,被远程引用时路径为${name}/${expose}
libraryobject声明全局变量的方式,name为umd的name
filenamestring构建输出的文件名
remotesobject远程引用的应用名及其别名的映射,使用时以key值作为name
exposesobject被远程引用时可暴露的资源路径及其别名
sharedobject与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

凶凌

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文