Runtime 接入

前置阅读

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

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

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

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

注册方式差异

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

若使用构建插件,项目启动时将自动创建 ModuleFederation 实例并存储于内存中。此时可直接调用 API,API 会自动从内存中获取构建运行时创建的 ModuleFederation 实例。

import { loadRemote } from '@module-federation/enhanced/runtime';

loadRemote('remote1');

若未使用构建插件,则需手动创建 ModuleFederation 实例,之后调用相应 API。

import { createInstance } from '@module-federation/enhanced/runtime';

const mf = createInstance({
  name: 'host',
  remotes: [
    {
      name: 'remote1',
      entry: 'http://localhost:2001/vmok-manifest.json',
    },
  ],
});

mf.loadRemote('remote1');
ModuleFederation 实例

ModuleFederation 类创建的对象,包含了运行时的所有功能。你可以在控制台输入 __FEDERATION__.__INSTANCES__ 来查看完整示例信息。

安装

不同项目需要安装不同的 Runtime 包,并直接从这些包中引用 Runtime API。

  • 大多数项目默认安装 @module-federation/enhanced
  • Modern.js 项目安装 @module-federation/modern-js-v3 插件

@module-federation/enhanced

npm
yarn
pnpm
bun
npm install @module-federation/enhanced --save
import { createInstance, loadRemote } from '@module-federation/enhanced/runtime';

Modern.js

npm
yarn
pnpm
bun
npm install @module-federation/modern-js-v3 --save
import { createInstance, loadRemote } from '@module-federation/modern-js-v3/runtime';
Note

如果是 Modern.js v2 项目,请安装 @module-federation/modern-js,并从 @module-federation/modern-js/runtime 引用 Runtime API。

模块注册

Build Plugin(使用构建插件)
Pure Runtime(未使用构建插件)
// 如果使用了构建插件,那么可以直接使用 `registerRemotes` 注册模块。
import { registerRemotes } from '@module-federation/enhanced/runtime';

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

模块加载

Build Plugin(使用构建插件)
Pure Runtime(未使用构建插件)
// 如果使用了构建插件,那么可以直接使用 `loadRemote` 加载模块。
import { loadRemote } from '@module-federation/enhanced/runtime';
import React from 'react';

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

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

加载匿名模块

Build Plugin(使用构建插件)
Pure Runtime(未使用构建插件)
// 如果使用了构建插件,那么可以直接使用 `loadRemote` 加载模块。
import React from 'react';
import { loadRemote } from '@module-federation/enhanced/runtime';

const RemoteButton = React.lazy(() => loadRemote('provider/button'));
// 也可通过模块别名加载:
// const RemoteButton = React.lazy(() => loadRemote('remotes-1/button'));

export default () => {
  return (
    <React.Suspense fallback="Loading Button">
      <RemoteButton />
    </React.Suspense>
  );
}

加载具名模块

Build Plugin(使用构建插件)
Pure Runtime(未使用构建插件)
// 如果使用了构建插件,那么可以直接使用 `loadRemote` 加载模块。
import React from 'react';
import { loadRemote } from '@module-federation/enhanced/runtime';

export default () => {
  const RemoteButton = React.lazy(() =>
    loadRemote('remote1/button').then(({ RemoteButton }) => {
      return {
        default: RemoteButton
      };
    }),
  );
  return (
    <React.Suspense fallback="Loading Button">
      <RemoteButton />
    </React.Suspense>
  );
}

加载工具函数

Build Plugin(使用构建插件)
Pure Runtime(未使用构建插件)
// 如果使用了构建插件,那么可以直接使用 `loadRemote` 加载模块。
import React from 'react';
import { loadRemote } from '@module-federation/enhanced/runtime';

// 加载 remote1 expose 的 util
loadRemote<{ add: (...args: Array<number>) => number }>('remote1/util').then((md) => {
  md.add(1, 2);
});

继续阅读

  • Runtime API:查看 createInstanceloadRemoteregisterRemotes 等 API。
  • Runtime 插件:了解如何扩展运行时加载流程。
  • Runtime Hooks:查看插件可使用的生命周期。