出处:掘金
原作者:金泽宸
模块联邦是“架构级代码共享”方案,是构建可插拔式系统的关键能力
写在前面
当前端团队规模扩大,每个业务线都拥有独立项目后,会面临这些问题:
- 如何让多个前端项目解耦、独立部署又能组合展示?
- 如何让子团队独立开发、独立上线,又共享公共组件?
- 如何解决“更新公共组件 A 要打所有项目包”的痛点?
这就是微前端与模块联邦(Module Federation)登场的地方
这一篇我们将:
- 掌握微前端 2 种主流架构(qiankun + Module Federation)
- 基于 Vite + Vue3 实战实现“模块联邦共享组件”
- 对比常见痛点与适配策略
微前端 VS. 模块联邦
特性 | qiankun(框架型) | Module Federation(构建型) |
---|---|---|
实现方式 | 运行时沙箱、iframe-like | 构建时拆包、共享模块 |
技术适配 | 所有框架(Vue/React/Angular) | Webpack5/Vite(需插件) |
加载方式 | HTML + JS 异步插入 | remoteEntry 动态加载 chunk |
场景优势 | 主子系统完全解耦 | 组件共享、统一系统更高效 |
弊端 | 沙箱隔离问题、通信复杂 | 构建依赖要求高、升级麻烦 |
实战:模块联邦架构
基于 Vite + Vue3
架构图:
┌────────────┐
│ host-app │ ──┬──加载子模块1(remote-app1)
└────────────┘ └──加载子模块2(remote-app2)
│
│
exposes: Button ← 远程共享组件 exposed 出来
项目结构预览:
micro-frontends/
├── host-app/ # 主应用
├── remote-app1/ # 子应用 1(暴露组件)
└── remote-app2/ # 子应用 2(暴露页面)
子应用 remote-app1(暴露组件)
安装依赖(vite-module-federation):
npm i -D @originjs/vite-plugin-federation
vite.config.ts
设置模块暴露:
// remote-app1/vite.config.ts
import federation from '@originjs/vite-plugin-federation'
export default {
plugins: [
federation({
name: 'remote_app1',
filename: 'remoteEntry.js',
exposes: {
'./FancyButton': './src/components/FancyButton.vue',
},
shared: ['vue'],
}),
],
build: {
target: 'esnext',
minify: false,
cssCodeSplit: false,
},
}
主应用 host-app(远程加载子模块)
vite.config.ts
中 remote
配置:
// host-app/vite.config.ts
import federation from '@originjs/vite-plugin-federation'
export default {
plugins: [
federation({
name: 'host',
remotes: {
remote_app1: 'http://localhost:5001/assets/remoteEntry.js',
},
shared: ['vue'],
}),
],
}
在主应用中动态引入远程组件:
// host-app/src/App.vue
<script setup>
import { defineAsyncComponent } from 'vue'
const RemoteButton = defineAsyncComponent(() =>
import('remote_app1/FancyButton')
)
</script>
<template>
<h2>主应用加载远程按钮:</h2>
<RemoteButton />
</template>
效果:主应用无需打包 remote
的 FancyButton
,即可直接使用远程子项目的组件
典型痛点与应对策略
问题 | 应对方案 |
---|---|
子项目变动导致主项目构建失败 | 使用 external 配置,主项目懒加载 |
多个项目依赖 vue 不一致 | 设置 shared: { vue: { singleton: true, requiredVersion: '^3.3' } } |
本地调试 remote 加载失败 | 使用 nginx 本地代理 + Vite dev config |
远程组件样式不一致 | 建议 remote 封装 UI 样式隔离(Scoped or BEM) |
类型提示丢失 | 搭配 @types/remote-module 或 .d.ts 模拟暴露模块 |
实战建议与落地模式
推荐使用场景:
- 多业务线组件库共享(如:Button / Table / Card)
- 配置平台 + 运营活动平台共享模块
- 低代码平台组件运行时按需加载
- 设计平台实时预览远程组件能力
- 高并发系统的按需拆包加载降初包体积
构建部署建议(CI/CD)
- 子项目构建后上传 remoteEntry 到 CDN
- 主项目运行时读取 CDN 地址
- 可设置版本号,如:
remotes: {
remote_app1: `https://cdn.xxx.com/remote-app1/1.0.0/remoteEntry.js`,
}
微前端实战对比(qiankun)
场景 | 推荐方式 |
---|---|
系统完全解耦、独立部署 | qiankun |
只想共享组件 / hook / 模块 | Module Federation |
公司已有主子仓库、统一权限 | qiankun |
想要按需加载优化包体积 | Module Federation |