Runtime 接入

Tip

在阅读本章前,预设你已经了解:

目前 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 实例是 ModuleFederation 类的实例,它包含了 ModuleFederation 运行时的所有功能。

你可以在控制台输入 __FEDERATION__.__INSTANCES__ 来查看已经创建好的实例。

安装

不同项目需要安装和引用不同的 Runtime 入口。大多数项目默认安装 @module-federation/enhanced,并从 @module-federation/enhanced/runtime 引用 Runtime API。Modern.js 项目如果已经使用 Module Federation 插件,应该从对应插件的 /runtime 入口引用 Runtime API,保证框架插件和手动调用的 Runtime 使用同一个实例。

@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';

如果是 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:查看插件可使用的生命周期。