webpack5--Module Federation摸索

781 阅读3分钟

概念

模块联邦 :Module Federation

  • Module Federation的动机 是为了不同开发小组共同开发一个或者多个应用
  • 应用将被划分为更小的应用块,一个应用块,可以是比如头部导航,或者侧边栏的前端组件,也可以是数据获取逻辑的逻辑组件
  • 每一个应用块由不同的组开发
  • 应用或者应用块共享其他应用块或者库

组成

容器

  • 使用Module Federation时,每个应用块都是一个独立的构建,这些构建都将编译为容器
  • 容器可以被其他应用或者其他容器应用

remote

  • 一个被引用的容器被称为remote,remote暴露模块给host

host

  • 引用者则为host,使用remote模块暴露出来的模块

关系图

模块是可以相互依赖 image.png

实践

初始化

  • 文件结构 image.png

  • 分别都初始化

npm init -y
yarn add webpack webpack-cli webpack-dev-server html-webpack-plugin babel-loader @babel/core @babel/preset-env @babel/preset-react style-loader css-loader --save-dev
yarn add react react-dom --save

脚本命令

  • package.json(host和remote配置相同)
 "scripts": {
    "build": "webpack",
    "start": "webpack serve"
  },

脚本命令和webpack4的区别: "start":"webpack-dev-server"

webpack.config

  • require 内置plugin :ModuleFederationPlugin
  • 实例化: new ModuleFederationPlugin
  • 配置导出 模块
    1. name:输出模块名,被远程引用路径为${name}/${expose}
    2. filename:构建输出的文件名这个和项目自己独立打包的输出main.js是相互独立的,前者是打包出来给别人用的,后者是自己的独立构建时候的最终打包文件
    3. remotes :远程引用的应用名&其别名的映射,使用时以key值为name,,此处的remote 指向的就是 被引用者 remote 输出的模块名称
    4. shared :与其他应用之间可以共享的第三方依赖,减少代码中不用重复加载同一份公共依赖 remote里的模块的import依赖, 在被引用的时候 的公共依赖最后 引的是引用者host里的依赖
    5. exposes:被远程引用时可暴露的资源路径及其别名
  • 核心代码

remote(webpack.config.js)

 devServer: {
    port: 3000,
  },
plugins: [
    new ModuleFederationPlugin({
      filename: "remoteEntry.js",
      name: "remote", //name string 必传值,
      exposes: {
        "./NewList": "./src/NewList",//要暴露出去的公共模块
      },
      shared: {
        react: { singleton: true },
        "react-dom": {
          singleton: true,
        },
      },
    }),
  ],

remote NewList组件

import React from 'react'
export default ()=>{
    return <div>新闻列表</div>
}

host(webpack.config.js)

引入我们要引用的模块

 plugins: [
    new ModuleFederationPlugin({
      remotes: {
        remote: "remote@http://localhost:3000/remoteEntry.js", 
      },
    }),
  ],

host(App.js)

import React from "react";
const RemoteNewList = React.lazy(() => import("remote/NewList"));

const App = () => {
  return (
   <div>
      <h2>本地组件Slider</h2>
      <Slider />
      {/*  Suspense 做一个loading*/}
      <React.Suspense fallback={<div>加载中....</div>}>
        <RemoteNewList />
      </React.Suspense>
    </div>
  );
};
export default App;

测试结果:

  • 成功渲染了remote项目里 NewList组件

第一次链接 remote的结果.png

实现双向依赖

remote 也可以是 引用者 作为host

host(webpack.config.js)

plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
    new ModuleFederationPlugin({
      filename: "remoteEntry.js", 
      name: "host", 
      remotes: {
        remote: "remote@http://localhost:3000/remoteEntry.js", 
      },
      exposes: {
        "./Slider": "./src/Slider",
      },
      shared: {
        react: { singleton: true },
        "react-dom": {
          //重复引用相同模块依赖
          singleton: true,
        },
      },
    }),
  ],

remote(App.js)

import React from "react";
import Slider from "./Slider";
const RemoteNewList = React.lazy(() => import("remote/NewList"));
const App = () => {
  return (
    <div>
      <h2>本地组件Slider</h2>
      <Slider />
      {/*  Suspense 做一个loading*/}
      <React.Suspense fallback={<div>加载中....</div>}>
        <RemoteNewList />
      </React.Suspense>
    </div>
  );
};
export default App;

测试结果

image.png

最后 码字不易 如果觉得本文有帮助 记得点赞三连哦 十分感谢