For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/guide/advanced/module-federation.md.
close
  • 简体中文
  • 模块联邦

    模块联邦(Module Federation) 支持不同应用在独立构建后,于运行时暴露和消费模块。当你需要确认消费者能否加载真实的生产者、解析共享依赖并正确执行暴露模块时,可以用 Rstest 测试这条联邦边界。

    @module-federation/rstest 为 Rstest 构建配置模块联邦。它支持 Node 和 JSDOM 测试环境以及 Browser Mode。

    安装

    @module-federation/rstest 添加到现有 Rstest 项目。

    npm
    yarn
    pnpm
    bun
    deno
    npm add @module-federation/rstest -D

    该插件只负责配置消费远程模块的测试消费者。生产者仍需使用自己的模块联邦构建插件进行构建,例如 Rslib 的 mf 格式

    基本用法

    注册 federation 插件,并使用与应用代码导入一致的生产者名称。最简单的形式是消费一个构建到本地 CommonJS 入口的 Node 生产者,不需要启动任何服务:

    rstest.config.ts
    import path from 'node:path';
    import { federation } from '@module-federation/rstest';
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      plugins: [
        federation({
          name: 'host',
          remoteType: 'commonjs',
          remotes: {
            remote: `commonjs ${path.resolve(__dirname, '../remote/dist/mf/remoteEntry.cjs')}`,
          },
        }),
      ],
    });

    然后像应用代码一样,通过远程模块的标识符导入暴露模块。使用动态 import() 加载,可以让生产者容器先完成初始化:

    tests/federated-modules.test.ts
    import { expect, test } from '@rstest/core';
    
    test('calls the federated formatPrice module', async () => {
      const { default: formatPrice } = await import('remote/formatPrice');
    
      expect(formatPrice(1250)).toBe('$12.50');
    });

    这种方式会实际经过远程模块加载和模块联邦运行时,而不是用 mock 替换联邦边界。为了通过类型检查,在 remotes.d.ts 里声明这些远程模块:

    remotes.d.ts
    declare module 'remote/formatPrice' {
      const formatPrice: (cents: number, currency?: string) => string;
      export default formatPrice;
    }

    配置远程模块

    federation() 插件接受和模块联邦构建插件相同的选项:remotessharedremoteType 等。测试里要注意两点:

    • 远程入口的目标环境。 Node 和 JSDOM 测试运行在 Rstest 的 Node runner 里,所以要指向面向 Node 的远程入口,例如 remoteEntry.cjs。Browser Mode 消费的是浏览器构建产物中的 remoteEntry.js
    • HTTP 生产者。 通过 HTTP 提供的生产者写成 remote@http://localhost:3001/remoteEntry.cjs 这样的地址,并设置 remoteType: 'script'。服务要在测试运行前启动,见globalSetup 启动生产者

    插件和 federation 配置项的关系

    federation 配置项只是 Rstest 内部的运行时兼容开关。它负责安装垫片,让模块联邦运行时能在 Rstest 的 Node worker 里加载 chunk,本身不配置任何模块联邦的内容:没有远程模块,没有暴露模块,也没有共享依赖。

    federation() 插件才做真正的配置,并且在基于 Node 的测试环境下会自动打开这个开关。因此在 Node 和 JSDOM 测试里使用插件时,不需要再设置 federation: true。Browser Mode 的情况不同,见 Browser mode

    globalSetup 启动生产者

    通过 HTTP 提供的生产者,必须在测试 worker 导入消费者应用之前就能访问。使用 globalSetup 统一启动服务,并在 teardown 里停止,不要在每个测试文件里各起一次:

    global-setup.ts
    import { createServer, type Server } from 'node:http';
    
    let server: Server;
    
    export async function setup() {
      server = createServer(/* 提供生产者的构建产物 */);
      await new Promise<void>((resolve) => server.listen(3001, resolve));
    }
    
    export async function teardown() {
      await new Promise<void>((resolve) => server.close(() => resolve()));
    }
    rstest.config.ts
    export default defineConfig({
      globalSetup: './global-setup.ts',
      // ...
    });

    Browser mode

    当生产者必须在真实浏览器中运行时,先配置 Browser Mode,然后在该项目的 Rstest 配置中保留同一个 federation 插件。插件会从解析后的配置中检测 browser.enabled,改用 Web 端的模块联邦运行时,而不是 Node 专用默认值。远程入口要指向浏览器构建产物中的 remoteEntry.js

    rstest.config.ts
    import { federation } from '@module-federation/rstest';
    import { pluginReact } from '@rsbuild/plugin-react';
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      federation: true,
      globalSetup: './global-setup.ts',
      browser: {
        enabled: true,
        provider: 'playwright',
      },
      plugins: [
        pluginReact(),
        federation({
          name: 'host',
          remoteType: 'script',
          remotes: { remote: 'remote@http://localhost:3001/mf/remoteEntry.js' },
          shared: {
            react: { singleton: true },
            'react-dom': { singleton: true },
          },
        }),
      ],
    });

    Browser Mode 下插件不会自动打开 federation 配置项。但 globalSetup 文件始终在 Node 进程里执行,产物里同样带着模块联邦运行时,没有这个开关,globalSetup 文件一加载就会报错,生产者服务也就起不来。所以 Browser Mode 项目只要用了 globalSetup,就要手动写上 federation: true

    了解更多

    • federation 参考文档介绍了独立配置项、CLI flag 和 Rstest 运行时行为。
    • Rstest 官方集成指南介绍了如何复用 Rsbuild 的模块联邦配置、插件选项和生产者构建。
    • Node 示例:用 Rslib 构建的本地 CommonJS 生产者,不需要 HTTP 服务。
    • Browser 示例:通过 HTTP 提供的联邦 React 组件,在 Chromium 中测试。