开始使用
在 Modern.js 中使用 Module Federation 我们推荐使用官方插件 @module-federation/modern-js
。
本章节将会介绍如何通过官方插件搭含生产者应用与消费者应用,我们首先根据 Modern.js 快速上手 创建两个应用。
安装插件
完成应用创建后,我们分别为两个项目安装插件:
npm add @module-federation/modern-js
注册插件
安装插件后,你需要在 modern.config.js
中注册插件:
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';
export default defineConfig({
runtime: {
router: true,
},
plugins: [
appTools({
bundler: 'rspack',
}),
moduleFederationPlugin(),
],
});
生产者导出模块
接下来,我们先修改生产者的代码,导出 Module Federation 模块。
我们创建 src/components/Button.tsx
文件,导出一个 Button 组件:
src/components/Button.tsx
import React from 'react';
export const Button = () => {
return <button type="button">Remote Button</button>;
};
随后,在项目根目录添加 module-federation.config.ts
,配置 Module Federation 模块的名称、共享依赖和导出内容:
module-federation.config.ts
import { createModuleFederationConfig } from '@module-federation/modern-js';
export default createModuleFederationConfig({
name: 'remote',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button.tsx',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
});
另外,我们还需要修改 modern.config.ts
,为生产者提供一个开发环境的端口,让消费者可以通过此端口访问生产者的资源:
modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';
export default defineConfig({
dev: {
port: 3051,
},
runtime: {
router: true,
},
plugins: [
appTools({
bundler: 'rspack',
}),
moduleFederationPlugin(),
],
});
消费者使用模块
现在,我们修改消费者的代码,使用生产者导出的模块。
在项目根目录添加 module-federation.config.ts
,配置 Module Federation 模块的名称、共享依赖和使用的远程模块:
module-federation.config.ts
import { createModuleFederationConfig } from '@module-federation/modern-js';
export default createModuleFederationConfig({
name: 'host',
remotes: {
remote: 'remote@http://localhost:3051/mf-manifest.json',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
});
mf-manifest.json
是生产者在打包后产出的文件,包含了生产者导出的所有模块信息。
我们创建新的路由文件 src/routes/remote/page.tsx
,引入生产者模块:
src/routes/remote/page.tsx
import React, { useState, Suspense } from 'react';
import { Button } from 'remote/Button';
const Index = (): JSX.Element => {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<Button />
</Suspense>
</div>
);
};
export default Index;
此时 remote/Button
引入会出现类型错误,这是因为本地没有远程模块的类型。Module Federation 2.0 提供了 类型提示 的能力,会在生产者构建时自动生成远程模块的类型定义,在消费者构建时自动下载。
为此我们需要在 tsconfig.json
中添加新的 path
,保证类型生效:
tsconfig.json
{
"compilerOptions": {
"paths": {
"*": ["./@mf-types/*"]
}
}
}
TIP
在消费者中,我们通过 remote/Button
来引用远程模块。这里简单介绍下这个路径具体代表了什么,可以先将它抽象成 [remoteAlias]/[remoteExpose]
。
第一段 remoteAlias
是生产者在消费者中的别名,它是消费者 module-federation.config.ts
中配置的 remotes
字段的 key
:
{
remotes: {
[remoteAlias]: '[remoteModuleName]@[URL_ADDRESS]',
}
}
这里我们也将远程地址抽象为 [remoteModuleName]@[URL_ADDRESS]
,@
前的部分必须对应生产者的模块名。
第二段 remoteExpose
是生产者在 module-federation.config.ts
中配置的 exposes
字段的 key
。
启动应用
现在,生产者应用和消费者应用都已经搭建完毕,我们可以在本地运行 modern dev
启动两个应用。
启动后,消费者中对生产者模块的引入,不会再出现抛错,类型已经下载到消费者应用中。
访问 http://localhost:8080/remote
,可以看到页面中已经包含了生产者的远程模块 Button
组件。
上述用例可以参考:Modern.js & Module Federation 基础用法示例。
相关文档