Skip to content

第11章 Module Federation 2.0 与 Rspack

"模块联邦的第一个版本证明了跨构建产物共享代码是可行的——而第二个版本证明了这件事可以变得简单、安全、且极其快速。"

本章要点

  • 理解 Module Federation 2.0 相比 1.0 的三大飞跃:类型安全、运行时插件系统、动态远程加载
  • 掌握 Rspack 中 Module Federation 的配置与 Rust 编译带来的性能优势
  • 深入 @module-federation/enhanced 运行时核心源码,理解模块加载与版本协商的底层机制
  • 实现跨框架(React + Vue)的 Module Federation 实践方案
  • 建立 MF 2.0 在生产环境的部署策略:版本管理、灰度发布、容灾降级

2022 年底的一个深夜,我正在调试一个 Webpack 5 Module Federation 的线上问题。远程模块加载失败了,但错误信息只有一行冷冰冰的 ScriptExternalLoadError。没有类型提示告诉我远程模块的接口长什么样,没有运行时钩子让我在加载失败时做降级处理,甚至无法在不重新部署宿主应用的情况下切换远程模块的地址。

我花了四个小时定位问题——最终发现是远程应用的一次接口变更导致类型不匹配,而宿主应用在编译期对此一无所知。

这就是 Module Federation 1.0 的困境:它打开了一扇通往跨应用模块共享的大门,却没有在门口放一盏灯。

2024 年,Zack Jackson 和团队发布了 Module Federation 2.0。这不是一次小版本迭代,而是一次架构级的重构。类型安全、运行时插件、动态远程、跨构建工具支持——这些能力让 Module Federation 从"能用"进化到"好用"。而 Rspack 的加入,则让"好用"变成了"飞快"。

本章将带你完整走过这条进化之路。

下图展示了 Module Federation 从 1.0 到 2.0 的架构跃迁,以及 Rspack 带来的编译性能提升:

11.1 MF 2.0 的新能力

Module Federation 1.0 解决了一个根本问题:如何在运行时从另一个独立部署的应用中加载模块。但它留下了三个关键缺口——类型安全、运行时扩展性、动态远程管理。MF 2.0 逐一填补了这些缺口。

11.1.1 类型安全:@module-federation/typescript

在 MF 1.0 中,远程模块对宿主应用而言是一个黑盒。你通过字符串引用一个远程模块,TypeScript 编译器对它的类型一无所知。MF 2.0 通过 @module-federation/typescript 引入了完整的类型安全机制——远程应用在构建时生成类型声明,宿主应用在开发时自动拉取。

typescript
// remote-app/rspack.config.ts(远程应用配置)
import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';

export default {
  plugins: [
    new ModuleFederationPlugin({
      name: 'remoteApp',
      filename: 'remoteEntry.js',
      exposes: {
        './Button': './src/components/Button.tsx',
        './UserCard': './src/components/UserCard.tsx',
        './useAuth': './src/hooks/useAuth.ts',
      },
      dts: {
        generateTypes: {
          extractRemoteTypes: true,
          compileInChildProcess: true,
        },
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
      },
    }),
  ],
};

宿主应用的配置负责消费这些类型:

typescript
// host-app/rspack.config.ts(宿主应用配置)
import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';

export default {
  plugins: [
    new ModuleFederationPlugin({
      name: 'hostApp',
      remotes: {
        remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
      },
      dts: {
        consumeTypes: {
          remoteTypesFolder: '@mf-types',
          abortOnError: false,
          consumeAPITypes: true,
        },
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
      },
    }),
  ],
};

配置完成后,宿主应用引用远程模块时便获得了完整的类型推导:

typescript
// host-app/src/App.tsx —— 完整的类型推导
import RemoteButton from 'remoteApp/Button';
import { useAuth } from 'remoteApp/useAuth';

function App() {
  const { user, login, logout } = useAuth(); // ✅ 完整的类型推导
  return (
    <RemoteButton
      label="登录"        // ✅ string 类型
      onClick={login}     // ✅ () => void
      variant="primary"   // ✅ 联合类型自动补全
      // color={123}      // ❌ 编译期报错:不存在属性 'color'
    />
  );
}

类型同步的底层使用 TypeScript Compiler API 提取暴露模块的声明文件,打包为可下载归档,宿主应用开发时从远程拉取并解压到 node_modules/@mf-types/ 目录,最后生成 TypeScript path mapping。

💡 深度洞察:MF 2.0 的类型安全不仅仅是"开发体验的提升"。在微前端架构中,远程模块的接口变更是最常见的故障来源之一。类型系统将这类问题从"运行时崩溃"前移到"编译期报错"。在传统微服务架构中,API 契约通过 OpenAPI/Protobuf 来保障;而在微前端架构中,模块联邦的类型系统扮演的正是同样的角色。

11.1.2 运行时插件系统

下图展示了 MF 2.0 运行时插件系统的钩子执行流程,每个阶段都可以被插件拦截和扩展:

基于 VitePress 构建