mf-integrate

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

MF Scaffold — Add Module Federation to an Existing Project

MF脚手架——为现有项目添加Module Federation

Step 1: Detect project

步骤1:检测项目

Call the
mf-context
Skill (pass
$ARGUMENTS
) to collect MFContext.
If no bundler can be detected (no
rsbuild.config
,
rspack.config
,
webpack.config
,
modern.config
,
next.config
,
vite.config
found), this is likely a new project. Tell the user:
This looks like a new project. Run the following command to scaffold a full Module Federation project:
bash
npm create module-federation@latest
Then stop.
If MF is already configured (MFContext shows existing
remotes
or
exposes
), inform the user what is already configured and ask if they want to add/modify the configuration or stop.

调用
mf-context
Skill(传入
$ARGUMENTS
)以收集MFContext。
如果未检测到任何打包工具(未找到
rsbuild.config
rspack.config
webpack.config
modern.config
next.config
vite.config
),则这很可能是一个新项目。请告知用户:
这看起来是一个新项目。运行以下命令来搭建完整的Module Federation项目:
bash
npm create module-federation@latest
然后终止流程。
如果已配置MF(MFContext显示存在
remotes
exposes
配置),则告知用户已有的配置内容,并询问是否需要添加/修改配置或终止操作。

Step 2: Gather parameters

步骤2:收集参数

Ask the user the following questions (combine into one AskUserQuestion call):
  1. Role — What role should this app play?
    • consumer
      — loads modules from remote apps (default)
    • provider
      — exposes modules to other apps
    • both
      — exposes modules and loads remote modules
  2. App name — What should the MF name be for this app?
    • Suggest the
      name
      field from
      package.json
      (snake_case, no hyphens). Hyphens are not allowed in MF names.
  3. Role-specific:
    • If consumer or both: Do you want to connect to the public demo provider to see MF working immediately, or configure your own remotes?
      • demo
        — use the public demo provider (default for consumers)
      • custom
        — I'll specify my own remote URLs
    • If provider or both: What module(s) do you want to expose? Provide
      key: path
      pairs, e.g.
      ./Button: ./src/components/Button.tsx
      . If unsure, use
      '.' : './src/index'
      as a default.

向用户询问以下问题(合并为一次询问):
  1. 角色——此应用应扮演什么角色?
    • consumer
      ——从远程应用加载模块(默认值)
    • provider
      ——向其他应用暴露模块
    • both
      ——同时暴露模块并加载远程模块
  2. 应用名称——此应用的MF名称是什么?
    • 建议使用
      package.json
      中的
      name
      字段(采用蛇形命名,无连字符)。MF名称不允许包含连字符。
  3. 角色专属参数
    • 如果是消费者两者兼具:是否要连接到公开的演示提供者以立即查看MF运行效果,还是配置自定义远程应用?
      • demo
        ——使用公开演示提供者(消费者默认选项)
      • custom
        ——我将指定自己的远程URL
    • 如果是提供者两者兼具:要暴露哪些模块?请提供
      key: path
      格式的配置,例如
      ./Button: ./src/components/Button.tsx
      。若不确定,可使用默认配置
      '.' : './src/index'

Step 3: Build the MF config object

步骤3:构建MF配置对象

Construct the MF config based on the gathered parameters:
根据收集到的参数构建MF配置:

Remote entries (for consumer / both)

远程入口(消费者/两者兼具)

Demo provider (use when user chose
demo
):
ts
remotes: {
  'provider': 'rslib_provider@https://unpkg.com/module-federation-rslib-provider@latest/dist/mf/mf-manifest.json',
},
The demo provider exposes a React component at
'provider'
. The user can import it in their app:
tsx
import ProviderApp from 'provider';
Custom remotes (use when user chose
custom
): Ask the user to provide remote entries in the format
name: url
, then use them as-is.
演示提供者(当用户选择
demo
时使用):
ts
remotes: {
  'provider': 'rslib_provider@https://unpkg.com/module-federation-rslib-provider@latest/dist/mf/mf-manifest.json',
},
该演示提供者暴露了一个React组件,用户可在应用中通过以下方式导入:
tsx
import ProviderApp from 'provider';
自定义远程应用(当用户选择
custom
时使用): 请用户提供
name: url
格式的远程入口,直接使用用户提供的配置。

Exposes (for provider / both)

暴露模块(提供者/两者兼具)

Use the entries provided by the user. Example:
ts
exposes: {
  './Button': './src/components/Button.tsx',
},
使用用户提供的配置项。示例:
ts
exposes: {
  './Button': './src/components/Button.tsx',
},

Shared deps

共享依赖

Read
package.json
to check which frameworks are present. Set singletons accordingly:
  • If
    react
    +
    react-dom
    present: add both as
    { singleton: true }
  • If
    vue
    present: add as
    { singleton: true }
  • If both (rare): add all as singletons

读取
package.json
以检查当前项目使用的框架,并相应地设置单例模式:
  • 如果存在
    react
    +
    react-dom
    :将两者设置为
    { singleton: true }
  • 如果存在
    vue
    :将其设置为
    { singleton: true }
  • 如果两者都存在(罕见情况):将所有框架都设置为单例

Step 4: Generate files

步骤4:生成文件

Apply the correct pattern for the detected bundler:

根据检测到的打包工具应用对应的配置模式:

Rsbuild

Rsbuild

Detected by:
rsbuild.config.ts
/
rsbuild.config.js
in project root.
检测依据:项目根目录下存在
rsbuild.config.ts
/
rsbuild.config.js

4a. Create
module-federation.config.ts

4a. 创建
module-federation.config.ts

ts
import { createModuleFederationConfig } from '@module-federation/rsbuild-plugin';

export default createModuleFederationConfig({
  name: '<app-name>',
  // exposes: { ... },        // provider / both only
  // remotes: { ... },        // consumer / both only
  shareStrategy: 'loaded-first',
  shared: {
    // react + react-dom or vue — from Step 3
  },
});
ts
import { createModuleFederationConfig } from '@module-federation/rsbuild-plugin';

export default createModuleFederationConfig({
  name: '<app-name>',
  // exposes: { ... },        // 仅提供者/两者兼具时需要
  // remotes: { ... },        // 仅消费者/两者兼具时需要
  shareStrategy: 'loaded-first',
  shared: {
    // react + react-dom 或 vue —— 来自步骤3
  },
});

4b. Modify
rsbuild.config.ts

4b. 修改
rsbuild.config.ts

Add
pluginModuleFederation
to the plugins array:
diff
+import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
+import moduleFederationConfig from './module-federation.config';

 export default defineConfig({
   plugins: [
     pluginReact(),
+    pluginModuleFederation(moduleFederationConfig),
   ],
 });
在插件数组中添加
pluginModuleFederation
diff
+import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
+import moduleFederationConfig from './module-federation.config';

 export default defineConfig({
   plugins: [
     pluginReact(),
+    pluginModuleFederation(moduleFederationConfig),
   ],
 });

4c. Install

4c. 安装依赖

bash
pnpm add @module-federation/rsbuild-plugin

bash
pnpm add @module-federation/rsbuild-plugin

Modern.js

Modern.js

Detected by:
modern.config.ts
/
modern.config.js
in project root.
检测依据:项目根目录下存在
modern.config.ts
/
modern.config.js

4a. Create
module-federation.config.ts

4a. 创建
module-federation.config.ts

ts
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';

export default createModuleFederationConfig({
  name: '<app-name>',
  // exposes: { ... },        // provider / both only
  // remotes: { ... },        // consumer / both only
  shared: {
    // react + react-dom or vue — from Step 3
  },
});
ts
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';

export default createModuleFederationConfig({
  name: '<app-name>',
  // exposes: { ... },        // 仅提供者/两者兼具时需要
  // remotes: { ... },        // 仅消费者/两者兼具时需要
  shared: {
    // react + react-dom 或 vue —— 来自步骤3
  },
});

4b. Modify
modern.config.ts

4b. 修改
modern.config.ts

diff
+import { moduleFederationPlugin } from '@module-federation/modern-js-v3';

 export default defineConfig({
   plugins: [
     appTools(),
+    moduleFederationPlugin(),
   ],
 });
diff
+import { moduleFederationPlugin } from '@module-federation/modern-js-v3';

 export default defineConfig({
   plugins: [
     appTools(),
+    moduleFederationPlugin(),
   ],
 });

4c. For consumer: add type paths

4c. 消费者:添加类型路径

Modify
tsconfig.json
to resolve remote types:
diff
 {
   "compilerOptions": {
+    "paths": {
+      "*": ["./@mf-types/*"]
+    }
   }
 }
修改
tsconfig.json
以解析远程类型:
diff
 {
   "compilerOptions": {
+    "paths": {
+      "*": ["./@mf-types/*"]
+    }
   }
 }

4d. Install

4d. 安装依赖

bash
pnpm add @module-federation/modern-js-v3

bash
pnpm add @module-federation/modern-js-v3

Rspack

Rspack

Detected by:
rspack.config.ts
/
rspack.config.js
in project root.
检测依据:项目根目录下存在
rspack.config.ts
/
rspack.config.js

4a. Modify
rspack.config.ts
/
rspack.config.js

4a. 修改
rspack.config.ts
/
rspack.config.js

Add
ModuleFederationPlugin
and
experiments.asyncStartup
:
diff
+const { ModuleFederationPlugin } = require('@module-federation/enhanced/rspack');

 module.exports = {
+  experiments: {
+    asyncStartup: true,
+  },
   plugins: [
+    new ModuleFederationPlugin({
+      name: '<app-name>',
+      // exposes: { ... },   // provider / both only
+      // remotes: { ... },   // consumer / both only
+      shared: {
+        // from Step 3
+      },
+    }),
   ],
 };
Note:
experiments.asyncStartup
requires Rspack > 1.7.4.
添加
ModuleFederationPlugin
experiments.asyncStartup
diff
+const { ModuleFederationPlugin } = require('@module-federation/enhanced/rspack');

 module.exports = {
+  experiments: {
+    asyncStartup: true,
+  },
   plugins: [
+    new ModuleFederationPlugin({
+      name: '<app-name>',
+      // exposes: { ... },   // 仅提供者/两者兼具时需要
+      // remotes: { ... },   // 仅消费者/两者兼具时需要
+      shared: {
+        // 来自步骤3
+      },
+    }),
   ],
 };
注意:
experiments.asyncStartup
需要Rspack版本 > 1.7.4。

4b. Install

4b. 安装依赖

bash
pnpm add @module-federation/enhanced

bash
pnpm add @module-federation/enhanced

Webpack

Webpack

Detected by:
webpack.config.ts
/
webpack.config.js
in project root.
检测依据:项目根目录下存在
webpack.config.ts
/
webpack.config.js

4a. Modify
webpack.config.js

4a. 修改
webpack.config.js

diff
+const { ModuleFederationPlugin } = require('@module-federation/enhanced/webpack');

 module.exports = {
+  experiments: {
+    asyncStartup: true,
+  },
   plugins: [
+    new ModuleFederationPlugin({
+      name: '<app-name>',
+      filename: 'remoteEntry.js',
+      // exposes: { ... },   // provider / both only
+      // remotes: { ... },   // consumer / both only
+      shared: {
+        // from Step 3
+      },
+    }),
   ],
 };
diff
+const { ModuleFederationPlugin } = require('@module-federation/enhanced/webpack');

 module.exports = {
+  experiments: {
+    asyncStartup: true,
+  },
   plugins: [
+    new ModuleFederationPlugin({
+      name: '<app-name>',
+      filename: 'remoteEntry.js',
+      // exposes: { ... },   // 仅提供者/两者兼具时需要
+      // remotes: { ... },   // 仅消费者/两者兼具时需要
+      shared: {
+        // 来自步骤3
+      },
+    }),
   ],
 };

4b. Install

4b. 安装依赖

bash
pnpm add @module-federation/enhanced

bash
pnpm add @module-federation/enhanced

Next.js

Next.js

Detected by:
next.config.ts
/
next.config.mjs
/
next.config.js
in project root.
Deprecation warning:
@module-federation/nextjs-mf
only supports Pages Router (not App Router) and is no longer actively maintained. For new projects, consider using Rsbuild or Modern.js instead.
检测依据:项目根目录下存在
next.config.ts
/
next.config.mjs
/
next.config.js
弃用警告
@module-federation/nextjs-mf
仅支持Pages Router(不支持App Router),且不再积极维护。对于新项目,建议使用Rsbuild或Modern.js。

4a. Modify
next.config.mjs

4a. 修改
next.config.mjs

diff
+import { NextFederationPlugin } from '@module-federation/nextjs-mf';

 const nextConfig = {
   webpack(config, options) {
+    config.plugins.push(
+      new NextFederationPlugin({
+        name: '<app-name>',
+        filename: 'static/chunks/remoteEntry.js',
+        // exposes: { ... },   // provider / both only
+        // remotes: {          // consumer / both only
+        //   remote: `remote@http://localhost:3001/static/${options.isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
+        // },
+        shared: {},
+        extraOptions: {
+          exposePages: true,
+          enableImageLoaderFix: true,
+          enableUrlLoaderFix: true,
+        },
+      })
+    );
     return config;
   },
 };
diff
+import { NextFederationPlugin } from '@module-federation/nextjs-mf';

 const nextConfig = {
   webpack(config, options) {
+    config.plugins.push(
+      new NextFederationPlugin({
+        name: '<app-name>',
+        filename: 'static/chunks/remoteEntry.js',
+        // exposes: { ... },   // 仅提供者/两者兼具时需要
+        // remotes: {          // 仅消费者/两者兼具时需要
+        //   remote: `remote@http://localhost:3001/static/${options.isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
+        // },
+        shared: {},
+        extraOptions: {
+          exposePages: true,
+          enableImageLoaderFix: true,
+          enableUrlLoaderFix: true,
+        },
+      })
+    );
     return config;
   },
 };

4b. Enable local Webpack

4b. 启用本地Webpack

Add to
.env.local
:
NEXT_PRIVATE_LOCAL_WEBPACK=true
.env.local
中添加:
NEXT_PRIVATE_LOCAL_WEBPACK=true

4c. Install

4c. 安装依赖

bash
pnpm add @module-federation/nextjs-mf webpack -D

bash
pnpm add @module-federation/nextjs-mf webpack -D

Vite

Vite

Detected by:
vite.config.ts
/
vite.config.js
in project root.
检测依据:项目根目录下存在
vite.config.ts
/
vite.config.js

4a. Modify
vite.config.ts

4a. 修改
vite.config.ts

diff
+import { federation } from '@module-federation/vite';

 export default defineConfig({
   plugins: [
+    federation({
+      name: '<app-name>',
+      // exposes: { ... },   // provider / both only
+      // remotes: { ... },   // consumer / both only
+      shared: {
+        // from Step 3
+      },
+    }),
   ],
 });
diff
+import { federation } from '@module-federation/vite';

 export default defineConfig({
   plugins: [
+    federation({
+      name: '<app-name>',
+      // exposes: { ... },   // 仅提供者/两者兼具时需要
+      // remotes: { ... },   // 仅消费者/两者兼具时需要
+      shared: {
+        // 来自步骤3
+      },
+    }),
   ],
 });

4b. Install

4b. 安装依赖

bash
pnpm add @module-federation/vite

bash
pnpm add @module-federation/vite

Step 5: Auto-insert remote component (consumer / both only)

步骤5:自动插入远程组件(仅消费者/两者兼具)

Skip this step entirely for provider-only role.
Ask the user:
Do you want me to automatically add the remote component to your app's entry so you can see it working right away?
If the user says no, just show the code snippet as a reference and move on to Step 6.
If the user says yes:
纯提供者角色跳过此步骤。
询问用户:
是否需要我自动将远程组件添加至应用入口,以便您立即查看运行效果?
如果用户选择,则仅展示代码片段作为参考,然后进入步骤6。
如果用户选择

5a. Locate the entry file

5a. 定位入口文件

Search for the entry component file in this priority order:
BundlerCandidates (in order)
Rsbuild
src/App.tsx
,
src/App.jsx
,
src/App.js
Modern.js
src/routes/page.tsx
,
src/routes/page.jsx
Webpack / Rspack
src/App.tsx
,
src/App.jsx
,
src/App.js
,
src/index.tsx
,
src/index.jsx
Next.js
pages/index.tsx
,
pages/index.jsx
,
pages/index.js
Vite
src/App.tsx
,
src/App.jsx
,
src/App.js
Read the first file that exists. If none found, tell the user which file to modify manually and show the snippet — do not attempt blind writes.
按以下优先级搜索入口组件文件:
打包工具候选文件(优先级顺序)
Rsbuild
src/App.tsx
,
src/App.jsx
,
src/App.js
Modern.js
src/routes/page.tsx
,
src/routes/page.jsx
Webpack / Rspack
src/App.tsx
,
src/App.jsx
,
src/App.js
,
src/index.tsx
,
src/index.jsx
Next.js
pages/index.tsx
,
pages/index.jsx
,
pages/index.js
Vite
src/App.tsx
,
src/App.jsx
,
src/App.js
读取第一个存在的文件。如果未找到任何文件,告知用户需要手动修改的文件并展示代码片段——请勿尝试盲目写入。

5b. Determine remote name and import path

5b. 确定远程名称和导入路径

Use the remote name from the config generated in Step 4:
  • If demo provider: remote name is
    provider
    , import path is
    'provider'
  • If custom remotes: use the first remote name the user specified
使用步骤4中生成的配置里的远程名称:
  • 如果是演示提供者:远程名称为
    provider
    ,导入路径为
    'provider'
  • 如果是自定义远程应用:使用用户指定的第一个远程名称

5c. Edit the entry file

5c. 编辑入口文件

Add the import at the top of the file (after existing imports) and render the component inside the existing JSX return.
For React (Rsbuild / Rspack / Webpack / Vite)
Add import after the last existing import line:
tsx
import ProviderApp from 'provider';
Insert
<ProviderApp />
inside the existing JSX return. Find a natural place — inside a
<div>
, after existing content. Do not restructure the component; just append the element.
For Modern.js (
src/routes/page.tsx
)
Same pattern — add import and render
<ProviderApp />
in the returned JSX.
For Next.js (
pages/index.tsx
)
Same pattern — add import and render
<ProviderApp />
in the returned JSX.
在文件顶部(现有导入之后)添加导入语句,并在现有JSX的返回值中渲染该组件。
React项目(Rsbuild / Rspack / Webpack / Vite)
在最后一条导入语句后添加:
tsx
import ProviderApp from 'provider';
在现有JSX返回值中插入
<ProviderApp />
。选择合适的位置——例如在某个
<div>
内,现有内容之后。请勿重构组件,仅追加元素。
Modern.js
src/routes/page.tsx
采用相同模式——添加导入语句并在返回的JSX中渲染
<ProviderApp />
Next.js
pages/index.tsx
采用相同模式——添加导入语句并在返回的JSX中渲染
<ProviderApp />

5d. Add TypeScript declaration (if TypeScript project)

5d. 添加TypeScript声明(TypeScript项目)

Check if
tsconfig.json
exists. If it does, create
src/remote.d.ts
(or add to an existing
src/declarations.d.ts
/
src/env.d.ts
if present):
ts
declare module '<remote-name>' {
  const Component: React.ComponentType;
  export default Component;
}
Replace
<remote-name>
with the actual remote name (e.g.,
provider
).
检查是否存在
tsconfig.json
。如果存在,创建
src/remote.d.ts
(或添加至已有的
src/declarations.d.ts
/
src/env.d.ts
):
ts
declare module '<remote-name>' {
  const Component: React.ComponentType;
  export default Component;
}
<remote-name>
替换为实际的远程名称(例如
provider
)。

Provider: how to verify the exposed module

提供者:如何验证暴露的模块

Tell the user that after running the dev server, the manifest will be available at:
  • Rsbuild / Rspack / Webpack / Modern.js:
    http://localhost:<port>/mf-manifest.json
  • Next.js:
    http://localhost:<port>/static/chunks/remoteEntry.js
Another app can reference this app as a remote using:
ts
remotes: {
  '<app-name>': '<app-name>@http://localhost:<port>/mf-manifest.json',
},

告知用户启动开发服务器后,清单文件将在以下地址可用:
  • Rsbuild / Rspack / Webpack / Modern.js:
    http://localhost:<port>/mf-manifest.json
  • Next.js:
    http://localhost:<port>/static/chunks/remoteEntry.js
其他应用可通过以下配置将此应用作为远程应用引用:
ts
remotes: {
  '<app-name>': '<app-name>@http://localhost:<port>/mf-manifest.json',
},

Step 6: Summary

步骤6:总结

Output a concise summary:
  • What files were created or modified
  • What packages were installed
  • How to start the dev server (use existing script from
    package.json
    )
  • Next steps (e.g., add more remotes, configure shared deps, set up type generation)
输出简洁的总结内容:
  • 创建或修改了哪些文件
  • 安装了哪些依赖包
  • 如何启动开发服务器(使用
    package.json
    中的现有脚本)
  • 后续步骤(例如添加更多远程应用、配置共享依赖、设置类型生成)