什么是Module Federation2

Module Federation2概念

模块联合是一种 JavaScript 应用去中心化的架构模式(类似于服务器端的微服务)。它允许您在多个 JavaScript 应用程序(或微前端)之间共享代码和资源。这可以帮助您:

  1. 减少代码重复

  2. 提高代码可维护性

  3. 降低应用程序的整体大小

  4. 增强应用程序的性能

module federationv1和v2的区别是什么?

Module Federation 2.0 与 Webpack5 内置的 Module Federation 不同,它不仅提供模块导出、加载和依赖共享等核心功能,还提供额外的动态类型提示、Manifest、Federation Runtime 和 Runtime Plugin System。这些特性使得 Module Federation 更适合用作大型 Web 应用程序中的微前端架构。

特点

  • 代码共享、依赖复用
  • 资源清单(Manifest)
  • module federation runtime
  • 运行时插件系统(tapable实现)
  • 动态类型提示
  • Chrome 开发工具
  • Rspack 和 Webpack 支持

模块联邦并没有样式隔离机制, 这意味着, 当主子应用很有可能会互相造成样式污染

概念理解:生产者

通过 Module federation 构建插件设置了 exposes 暴露其他模块给其他 JavaScript 应用消费的应用在 Module federation 中称之为 Provider(生产者),生产者可以同时作为一个消费者。

概念理解:消费者

通过 Module federation 构建插件设置了 remotes 消费其他生产者的模块称之为 Consumer (消费者),消费者可以同时作为一个生产者。

@module-federation/enhanced

Module Federation 核心包,作为 Webpack 构建插件、 Rspack 构建插件、Runtime 入口依赖。

@module-federation/runtime

Module Federation 的 Runtime 包,通常使用 @module-federation/enhanced 来使用 Runtime 能力,若不需要使用构建工具时可单独安装此包。

概念目标

  • 它既可以暴露,又可以使用 webpack 支持的任何模块类型

  • 代码块加载应该并行加载所需的所有内容(web:到服务器的单次往返)

  • 从使用者到容器的控制

    • 重写模块是一种单向操作
    • 同级容器不能重写彼此的模块。
  • 概念适用于独立于环境

    • 可用于 web、Node.js 等
  • 共享中的相对和绝对请求

    • 会一直提供,即使不使用
    • 会将相对路径解析到 config.context
    • 默认不会使用 requiredVersion
  • 共享中的模块请求

    • 只在使用时提供
    • 会匹配构建中所有使用的相等模块请求
    • 将提供所有匹配模块
    • 将从图中这个位置的 package.json 提取 requiredVersion
    • 当你有嵌套的 node_modules 时,可以提供和使用多个不同的版本
  • 共享中尾部带有 / 的模块请求将匹配所有具有这个前缀的模块请求


使用

目前 Module Federation 提供了两种注册模块和加载模块的方式:

  1. 一种是在构建插件中声明(一般是在 module-federation.config.ts 文件中声明)

  2. 另一种方式是直接通过 runtime 的 api 进行模块注册和加载。

两种模式并不冲突可结合使用。你可以根据你的实际场景灵活选取模块注册方式和时机

运行时注册模块和构建配置注册模块的区别如下:

运行时注册模块 插件中注册模块
可脱离构建插件使用,在 webpack4 等项目中可直接使用纯运行时进行模块注册和加载 构建插件需要是 webpack5 或以上
支持动态注册模块 不支持动态注册模块
不支持 import 语法加载模块 支持 import 同步语法加载模块
支持 loadRemote 加载模块 支持 loadRemote 加载模块
设置 shared 必须提供具体版本和实例信息 设置 shared 只需要配置规则即可,无须提供具体版本及实例信息
shared 依赖只能供外部使用,无法使用外部 shared 依赖 shared 依赖按照特定规则双向共享
可以通过 runtimeplugin 机制影响加载流程 目前不支持提供 plugin 影响加载流程
不支持远程类型提示 支持远程类型提示

插件用法

快速创建项目

Module Federation 提供了 create-module-federation 工具来创建项目,不需要全局安装,直接使用 npx 按需运行即可。

模板

在创建项目时,你可以选择 create-module-federation 提供的下列模板:

模板 描述
provider-modern 使用 Modern.js 的生产者
provider-rsbuild 使用 Rsbuild 的生产者
provider-rslib 使用 Rslib 的生产者
provider-rslib-storybook 使用 Rslib 的生产者,并且开启了 storybook 功能
consumer-modern 使用 Modern.js 的消费者
consumer-rsbuild 使用 Rsbuild 的消费者

生产者, 提供组件

bash 复制代码
# 创建 my-project目录下创建mf-provider的生产者
npx create-module-federation --dir my-project --template provider-modern --name mf-provider
js 复制代码
import { createModuleFederationConfig } from "@module-federation/rsbuild-plugin";

export default createModuleFederationConfig({
  name: "mf-provider",
  exposes: {
    "./Provider": "./src/components/ProviderComponent.tsx",
  },
  shared: {
    react: { singleton: true },
    "react-dom": { singleton: true },
  },
});

消费者, 使用生产者

bash 复制代码
# 创建 my-project目录下创建mf-consumer的消费者
npx create-module-federation --dir my-project --template consumer-modern --name mf-consumer
js 复制代码
import { createModuleFederationConfig } from "@module-federation/rsbuild-plugin";

export default createModuleFederationConfig({
  name: "mf-consumer",
  remotes: {
    provider: "mf-provider@http://localhost:3001/mf-manifest.json",
  },
  shareStrategy: "loaded-first",
  shared: {
    react: { singleton: true },
    "react-dom": { singleton: true },
  },
});

import Provider from "provider/Provider";
<Provider></Provider>;

runtime用法

module federation v2允许我们在写运行时代码去加载远程模块,但是远程模块的导出还是交给了构建工具基于@module-federation/runtime去实现

example1

example2

这个git项目内还有很多使用案例

模块加载

tsx 复制代码
// 如果没有使用构建插件,那么可以创建新的实例,并注册模块
import { createInstance } from '@module-federation/enhanced/runtime';
import React from 'react';

const mf = createInstance({
  name: 'mf_host',
  remotes: [
    {
      name: 'remote1',
      alias: 'remote-1',
      entry: 'http://localhost:3001/mf-manifest.json',
    }
  ]
});

export default () => {
  const MyButton = React.lazy(() =>
    mf.loadRemote('remote1').then(({ MyButton }) => {
      return {
        default: MyButton
      };
    }),
  );

  return (
    <React.Suspense fallback="Loading Button">
      <MyButton />
    </React.Suspense>
  );
}

原理

  • 通过share的模块回自动在执行链路过程中生成share scope,而本地host和remote都会进行提供相对应的modules, 在进行使用的时候通过校验share scope中的provided模块是否符合当前的版本等信息,如果符合则进行加载模块并存储,从而达到了共享模块的母的

  • 模块加载是通过异步加载,只有在使用的时候才会进行加载对应的模块内容,在未加载前只存储对应的相关模块属性信息

juejin.cn/post/704812...

相关推荐
岁月宁静2 小时前
AI 聊天消息长列表性能优化:后端分页 + 前端虚拟滚动
前端·vue.js·人工智能
TZOF2 小时前
TypeScript的对象如何进行类型声明
前端·后端·typescript
一只叁木Meow2 小时前
DOM元素尺寸属性详解:offset、client、scroll
前端
原则猫2 小时前
单例模式工程运用
前端·设计模式
degree5202 小时前
使用 Web Vitals 量化网页性能:从 LCP、FID 到 CLS 实战优化
前端
水晶浮游2 小时前
💥 半夜3点被拉群骂?学会Sentry监控后,现在都是后端背锅了
前端
Olrookie2 小时前
若依前后端分离版学习笔记(十九)——导入,导出实现流程及图片,文件组件
前端·vue.js·笔记
浩男孩3 小时前
🍀终于向常量组件下手了,使用TypeScript 基于 TDesign二次封装常量组件 🚀🚀
前端·vue.js
玲小珑3 小时前
LangChain.js 完全开发手册(十三)AI Agent 生态系统与工具集成
前端·langchain·ai编程