Runtime 接入
目前 Module Federation 提供了两种注册模块和加载模块的方式:
两种模式并不冲突可结合使用。你可以根据你的实际场景灵活选取模块注册方式和时机
运行时注册模块和构建配置注册模块的区别如下:
| 运行时注册模块 | 插件中注册模块 |
|---|
可脱离构建插件使用,在 webpack4 等项目中可直接使用纯运行时进行模块注册和加载 | 构建插件需要是 webpack5 或以上 |
| 支持动态注册模块 | 不支持动态注册模块 |
不支持 import 语法加载模块 | 支持 import 同步语法加载模块 |
支持 loadRemote 加载模块 | 支持 loadRemote 加载模块 |
设置 shared 必须提供具体版本和实例信息 | 设置 shared 只需要配置规则即可,无须提供具体版本及实例信息 |
shared 依赖只能供外部使用,无法使用外部 shared 依赖 | shared 依赖按照特定规则双向共享 |
可以通过 runtime 的 plugin 机制影响加载流程 | 目前不支持提供 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__ 来查看已经创建好的实例。
安装
npm add @module-federation/enhanced --save
注意:
-
以下 Federation Runtime 示例我们均展示脱离特定框架如 Modern.js 的 case, 所以 API 将均从初始 @module-federation/enhanced/runtime 包中导出。
-
如果你的项目是 Modern.js 项目且使用 @module-federation/modern-js,运行时应该从 @module-federation/modern-js/runtime 中导出运行时 API。这样能保证插件和运行时使用的是同一个运行时实例,保证模块加载正常
-
如果你的项目是 Modern.js 项目但是没有使用 @module-federation/modern-js,则应当从 @module-federation/enhanced/runtime 导出 runtime API。但是我们推荐你使用 @module-federation/modern-js 进行模块注册和加载,这将使你享受到更多和框架结合的能力。
模块注册
// 如果使用了构建插件,那么可以直接使用 `registerRemotes` 注册模块。
import { registerRemotes } from '@module-federation/enhanced/runtime';
registerRemotes([
{
name: 'remote1',
alias: 'remote-1',
entry: 'http://localhost:3001/mf-manifest.json',
}
]);
模块加载
// 如果使用了构建插件,那么可以直接使用 `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>
);
}
加载匿名模块
// 如果使用了构建插件,那么可以直接使用 `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>
);
}
加载具名模块
// 如果使用了构建插件,那么可以直接使用 `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>
);
}
加载工具函数
// 如果使用了构建插件,那么可以直接使用 `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);
});