目前微前端领域已形成多种主流架构模式,每种方案各有适用场景。以下是当前(2025年)最主流的架构方案及其特点:
1. 路由分发式 (基座模式)
核心 :通过主应用(基座)控制路由分发,按需加载子应用
代表方案:
- single-spa:元框架,提供生命周期钩子(bootstrap/mount/unmount)
- qiankun (基于single-spa):阿里开箱方案,集成沙箱、样式隔离、通信机制
适用场景:多技术栈共存、渐进式迁移旧系统
php
// qiankun示例
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react-app',
entry: '//localhost:7100',
container: '#subapp',
activeRule: '/react'
}
]);
start();
2. 模块联邦 (Module Federation)
核心 :Webpack 5原生支持,动态加载远程模块
优势 :代码实时共享、无重复打包、依赖去重
典型场景:跨应用复用组件/工具库/状态管理
arduino
// webpack.config.js (宿主应用)
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: 'app1@http://cdn.com/app1/remoteEntry.js'
}
});
3. Web Components 方案
核心 :浏览器原生组件化,Shadow DOM实现样式隔离
方案:
- icestark:美团轻量方案,支持Web Components集成
- Bit :组件级微前端,独立部署组件
优势:技术栈无关、彻底隔离、长期兼容性好
xml
<!-- 直接使用自定义元素 -->
<micro-app src="https://example.com/subapp.js"></micro-app>
4. iframe 嵌套方案
核心 :传统隔离方案,利用浏览器沙箱机制
优化方案:
- Zalando的Tailor:服务端拼接HTML片段
- Piral :集成iframe作为插件容器
适用场景:强隔离需求(如第三方插件)、快速接入
5. 无界微前端
核心 :基于Web Components + iframe沙箱的创新方案
特点:
- 利用
Proxy
实现主子应用双向通信 - 原生级CSS/JS隔离(无需特殊编译)
- 极速启动(子应用并行预加载)
代表:腾讯无界微前端框架
技术选型关键维度
维度 | 路由分发 | 模块联邦 | Web Components | iframe |
---|---|---|---|---|
隔离性 | 中等(需配置) | 弱 | 强 | ⭐️最强 |
通信成本 | 中(自定义) | 低(模块导入) | 中(事件机制) | 高(postMessage) |
开发体验 | 复杂 | ⭐️便捷 | 中等 | 割裂 |
构建依赖 | 无 | 需Webpack 5 | 无 | 无 |
旧系统接入 | ⭐️友好 | 困难 | 中等 | ⭐️最易 |
实践建议
-
渐进迁移:老系统用qiankun/iframe接入,新模块用Module Federation共享
-
隔离策略:
- CSS:开启Shadow DOM或CSS Scoped(Vue)/ CSS Modules(React)
- JS:使用Proxy沙箱(qiankun)或浏览器原生隔离(Web Components)
-
状态管理:
- 轻量通信:CustomEvent + localStorage
- 复杂场景:共享Redux Store/Vuex/Pinia via Module Federation
-
部署独立:子应用独立CI/CD,主应用控制版本拉取策略(如蓝绿发布)
最新趋势 :2025年逐步流行Vite + 微前端 方案,利用Vite原生ESM支持实现秒级子应用加载,如
vite-plugin-federation
。
根据团队技术栈(React/Vue/Angular)和隔离性需求,可混合使用多种方案。建议从路由分发模式起步,逐步向模块联邦过渡实现更高复用性。
Vite + 微前端是当前最高效的微前端实现方案之一,利用 Vite 的原生 ESM 能力和构建速度,结合模块联邦实现组件级共享与秒级加载。以下是具体实现细节和最佳实践:
一、核心方案:vite-plugin-federation
原理 :
基于 Webpack Module Federation 规范,通过 Vite 的预构建和 ESM 加载能力实现跨应用模块共享。
bash
# 安装核心插件
npm install @originjs/vite-plugin-federation -D
二、具体实现步骤(以 React 项目为例)
1. 子应用配置(暴露模块)
javascript
// child-app/vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
plugins: [
react(),
federation({
name: 'child-app', // 应用唯一ID
filename: 'remoteEntry.js', // 远程入口文件
// 暴露需要共享的组件/模块
exposes: {
'./Button': './src/components/Button.jsx',
'./Store': './src/store/index.js'
},
shared: ['react', 'react-dom'] // 避免重复依赖
})
],
build: {
target: 'esnext' // 必须使用现代浏览器支持ESM
}
})
2. 主应用配置(消费远程模块)
javascript
// host-app/vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
plugins: [
react(),
federation({
name: 'host-app',
// 引用远程子应用模块
remotes: {
child: 'http://localhost:5001/assets/remoteEntry.js'
},
shared: ['react', 'react-dom']
})
]
})
3. 主应用动态加载子应用组件
javascript
// host-app/src/App.jsx
import React, { Suspense, lazy } from 'react';
// 异步加载子应用暴露的组件
const RemoteButton = lazy(() => import('child/Button'));
function App() {
return (
<div>
<h1>主应用</h1>
<Suspense fallback={<div>加载中...</div>}>
{/* 直接使用远程组件 */}
<RemoteButton />
</Suspense>
</div>
)
}
三、关键技术优化点
1. 依赖共享策略
arduino
// 共享依赖高级配置
shared: {
react: {
singleton: true, // 强制单例
eager: true // 预加载
},
'lodash': {
version: '4.17.21' // 指定版本避免冲突
}
}
2. CSS 隔离方案
-
方式1 :使用
vite-plugin-federation
自动注入 Scoped CSS -
方式2:手动开启 Shadow DOM
ini// 创建Shadow DOM容器 const shadowContainer = useRef(null); useEffect(() => { shadowContainer.current.attachShadow({ mode: 'open' }); }, []); return <div ref={shadowContainer} />;
3. 通信机制
javascript
// 子应用初始化时挂载全局方法
window.childApp = {
setData: (data) => { /* ... */ }
}
// 主应用调用
const remote = await import('child/Store');
remote.dispatch({ type: 'UPDATE', payload: data });
四、生产环境部署策略
1. 静态资源托管
bash
https://assets.example.com/
├── host-app/ # 主应用
│ ├── assets/
│ └── index.html
└── child-app/ # 子应用
├── assets/
│ └── remoteEntry.js # 联邦入口文件
└── resources/
└── Button.js # 按需加载的组件
2. Nginx 路由转发
bash
# 统一资源路径
location /federation {
proxy_pass https://assets.example.com; # CDN地址
add_header Access-Control-Allow-Origin *;
}
# 主应用HTML入口
location / {
root /usr/share/nginx/html/host-app;
try_files $uri $uri/ /index.html;
}
五、性能优化手段
- 子应用预加载
xml
<!-- 主应用index.html -->
<link
rel="modulepreload"
href="https://cdn.com/child-app/remoteEntry.js"
/>
- 按需加载策略
ini
// 动态判断是否加载子应用
const loadChildApp = () =>
userRole === 'admin' ? import('child/AdminPanel') : null;
- 构建优化
css
# 子应用分包配置(vite.config.js)
build: {
rollupOptions: {
output: {
manualChunks: {
react: ['react', 'react-dom'],
utils: ['lodash', 'axios']
}
}
}
}
六、框架支持度
框架 | 支持程度 | 关键特性 |
---|---|---|
React | ⭐️⭐️⭐️⭐️⭐️ | 完整的Hooks支持 |
Vue 3 | ⭐️⭐️⭐️⭐️ | 需配合vue-router 路由分割 |
Svelte | ⭐️⭐️⭐️ | 需手动配置CSS作用域 |
SolidJS | ⭐️⭐️⭐️⭐️ | 依赖自动追踪优化 |
七、与传统方案的对比优势
指标 | Webpack联邦方案 | Vite联邦方案 |
---|---|---|
冷启动速度 | 20s+ (需打包依赖) | <1s (ESM原生加载) |
HMR热更新 | 局部更新(2-4s) | 毫秒级更新 |
构建复杂度 | 需配置多个插件 | Vite开箱即用 |
包体积 | 包含运行时代码 | 纯ESM无运行时 |
浏览器兼容性 | 需babel转译 | 默认仅现代浏览器 |
实测数据:在100+组件的中大型项目中,子应用加载速度从Webpack方案的3.2s降至Vite方案的0.4s
实践建议
-
调试技巧:
- 开发时用
vite-plugin-federation-devtools
可视化模块依赖关系
javascriptimport devtools from 'vite-plugin-federation-devtools' plugins: [devtools()]
- 开发时用
-
安全隔离:
- 对敏感子应用开启
sandbox: true
限制DOM访问权限
- 对敏感子应用开启
-
渐进迁移:
php// 旧Webpack项目兼容 federation({ remotes: { legacy: 'webpack@http://old.com/remoteEntry.js' } })
随着 Vite 4.0+ 对联邦方案的深度优化,该模式已成为微前端领域的高性能首选方案,尤其适合需要频繁更新子模块的复杂应用场景。
什么是 Monorepo?
- Monorepo 是一种单一代码仓库策略 ,用于管理多个项目、库或包。
- 所有相关代码(前端应用、后端服务、共享库、工具脚本、配置文件等)都存放在同一个 Git 代码仓库中。
- 这与传统的 Multirepo(每个项目/包一个单独的仓库)形成鲜明对比。
一、 前端 Monorepo 的意义 (Why)
-
代码共享与复用最大化:
- 核心优势: 共享的 UI 组件库、工具函数、公共类型定义、配置(ESLint, Prettier, Babel, Webpack, TSConfig)等,可以直接放入 Monorepo 中作为内部包。任何项目都可以直接引用,无需通过 NPM/Yarn 发布安装,且能保证引用的是最新代码。
- 消除"依赖地狱": 避免在多个仓库之间复制粘贴代码或维护不同版本的公共包,减少重复劳动和版本不一致风险。
-
简化依赖管理与版本控制:
- 统一依赖安装: 所有子项目共享同一个顶级
node_modules
(通过工具如 npm/yarn/pnpm workspaces 或 Lerna/Nx 实现),减少磁盘空间占用,加快安装速度(尤其是 pnpm 的硬链接优势)。 - 原子级提交: 涉及多个项目或共享库的改动(如更新组件库并同时更新使用它的多个应用)可以放在一个 Commit/PR 中完成,方便代码审查、跟踪变更影响和回滚。
- 跨项目依赖升级: 升级一个公共依赖项(如 React 版本)可以在整个仓库中进行,更容易保证所有项目同步。
- 统一依赖安装: 所有子项目共享同一个顶级
-
统一规范与工具链:
- 一致性与标准化: 所有项目共享同一套代码风格规则(ESLint)、格式化规则(Prettier)、构建工具(Webpack/Vite)、测试框架(Jest/Cypress)、TypeScript 配置等。易于管理和维护统一的质量标准。
- 统一脚本: 可以定义仓库级的脚本命令(如
build-all
,test-all
,lint-all
),方便对整个仓库或受影响部分执行操作。
-
提升开发体验与效率:
- 本地交叉引用 (Cross-Linking): 开发模式下,修改共享库的代码可以实时被依赖它的其他项目感知和使用(热更新),无需手动发布到 NPM 或
npm link
。 - 单一仓库克隆: 开发者只需克隆一次仓库,即可获得开发多个项目所需的所有代码和环境,减少环境搭建的摩擦。
- 模块化开发: 项目可划分为多个独立的包,便于大型团队的职责划分与协作。每个包可以独立构建、测试、发布(如果需要)。
- 本地交叉引用 (Cross-Linking): 开发模式下,修改共享库的代码可以实时被依赖它的其他项目感知和使用(热更新),无需手动发布到 NPM 或
-
改善项目发现与理解:
- 清晰的架构: 整个前端生态(应用、库、工具)都集中在一个地方,方便新人理解项目间的依赖关系和整体架构。
- 代码导航简单化: IDE 和工具更容易索引和关联所有代码,便于搜索和跳转。
二、 前端 Monorepo 的使用场景 (When/Where)
-
大型或快速增长的前端项目:
- 前端项目逐渐复杂化,衍生出多个应用(如主站、管理后台、活动页)和共享库(组件库、工具函数、数据访问层)。Monorepo 是管理这种复杂性的天然选择。
-
拥有共享 UI 组件库或公共代码:
- 需要维护一个或多个在多个应用中复用的共享库(尤其是内部库)。Monorepo 是最适合高效开发和同步修改共享代码的环境。
-
需要高度标准化和统一流程的团队:
- 团队成员较多(>5人),需要强制执行统一的编码规范、构建配置、测试流程和发布流程。Monorepo 提供了集中式管理和执行的基础。
-
微前端架构:
- 采用微前端架构时,经常需要在一个仓库中管理多个独立部署的微前端应用(微应用),以及它们共享的依赖和组件库。Monorepo 是实施这种架构的常用技术底座(基础设施),它提供了完美的本地开发调试环境和一致的工具链保障。
-
全栈项目(包含前端和后端):
- 虽然主要问前端,但 Monorepo 常用于包含 Node.js 服务、共享类型定义、甚至基础设施即代码的前后端全栈项目,确保整个系统开发的一致性。前端部分作为整个 Monorepo 中的一个或多个子项目存在。
三、 前端 Monorepo 的实例 (Examples)
-
知名开源项目:
- Babel: 经典 JS 编译器,使用 Lerna + Yarn Workspaces 管理众多插件包和工具。
- React: Facebook 的 UI 库本身,以及其官网、文档(Next.js)、开发工具等都在一个巨大的 Monorepo 中(使用 Facebook 自研的工具链)。
- Vue.js: 核心库及其相关项目(Vuex, Vue Router, Vue CLI, Nuxt.js - Nuxt 本身也是 Monorepo)早期都是同一个 Monorepo(现主要项目如 Vue 3 核心采用 pnpm workspaces)。
- Next.js: Vercel 的 React 框架,核心框架、示例、文档等都在一个使用 pnpm workspaces 的 Monorepo 中。
- Material-UI (MUI): 流行的 React UI 库,使用 Yarn Workspaces 管理核心库、图标库、Lab、文档和示例应用。
- Nx: 本身就是一个强大的 Monorepo 开发工具套件,其文档、示例、插件等都管理在其自身的大型 Nx Monorepo 中。
- Pnpm: 包管理工具本身的项目也是一个使用 pnpm workspaces 的 Monorepo 典范。
-
典型商业项目结构(示例目录):
一个假设的中大型电商项目可能包含:
scss
ecommerce-monorepo/
├── .git/ # 单一 Git 仓库
├── node_modules/ # 根层级的 node_modules (由 workspaces 管理)
├── package.json # 根 package.json (定义 workspaces 和全局脚本)
├── pnpm-workspace.yaml # pnpm 工作区配置文件 (标识哪些目录是包)
├── apps/ # 存放前端应用(每个应用相当于一个独立项目)
│ ├── main-website/ # 主站 (Next.js/React)
│ │ ├── package.json
│ │ └── src/
│ ├── admin-console/ # 管理后台 (Vue.js)
│ │ ├── package.json
│ │ └── src/
│ └── promotion-micro/ # 微前端 - 促销活动页 (独立部署的 Vue)
│ ├── package.json
│ └── src/
├── packages/ # 存放共享库/内部包
│ ├── ui-kit/ # 共享 UI 组件库 (React/Vue Components & Styles)
│ │ ├── package.json
│ │ ├── src/ # 组件源代码
│ │ └── dist/ # 构建产物 (可选, 可能在 root 统一构建)
│ ├── utils/ # 共享工具函数库 (TypeScript)
│ │ ├── package.json
│ │ └── src/
│ ├── api-client/ # 统一的 API Client (基于 Axios)
│ │ ├── package.json
│ │ └── src/
│ └── types/ # 共享的 TypeScript 类型定义
│ ├── package.json
│ └── src/
├── libs/ # (可选) 更底层的库或后端服务 (如果包含全栈)
│ └── order-service/ # Node.js 微服务
│ ├── package.json
│ └── src/
├── tools/ # (可选) 仓库级脚本或工具
│ └── migration-scripts/
└── configs/ # 集中存放共享配置 (可以被各子包继承或扩展)
├── eslint/
├── prettier/
├── tsconfig/ # Base tsconfig.json
└── jest/
关键点:
-
apps/: 包含可部署的前端应用。
-
packages/ : 包含可被多个
apps
和packages
引用的内部共享库。 -
根配置文件 (
package.json
,pnpm-workspace.yaml
): 定义工作区范围、全局依赖和脚本。 -
依赖管理: 在
apps/main-website/package.json
中,可以这样引用共享库:less{ "dependencies": { "@your-org/ui-kit": "workspace:*", // 直接引用同仓库中的包 "react": "18.2.0" } }
workspace:*
表示引用该包在packages/ui-kit
下的最新源码(在构建或启动时会自动链接)。
四、 Monorepo 工具
实施前端 Monorepo 通常需要工具支持:
-
包管理器的工作区 (Workspaces) 功能:
- Yarn Workspaces: 成熟稳定,社区支持好。
- PNPM Workspaces: 速度快(磁盘空间利用效率高),链接安全,目前是前端生态中的主流选择之一。
- NPM Workspaces (>= v7): 原生支持,功能不断追赶 Yarn/PNPM。
-
Monorepo 管理工具 (常搭配 Workspaces 使用):
- Lerna: 历史悠久,专注于版本管理和发布。常与 Yarn/NPM Workspaces 结合(运行命令、管理版本)。
- Nx: 强大的构建系统 (task scheduling, caching, remote caching) 和 Monorepo 管理工具。功能远超 Lerna,提供强大开发体验 (VS Code 插件)、代码生成器、依赖可视化等。适合大型复杂项目。
- Rush: Microsoft 开源的,专为极大规模 Monorepo 设计的工具链,包含安装链接构建发布等全流程优化。
- Turborepo: Vercel 出品,专注于极快的 Monorepo 本地和远程构建缓存 (Remote Caching)。轻量级任务运行器,易于集成到现有项目中。
五、 使用 Monorepo 的注意事项
- 初始学习曲线和工具链复杂性: 引入 Monorepo 通常意味着更复杂的工具链(Yarn/Pnpm Workspaces + Lerna/Nx/Rush/Turbo),团队需要学习适应。
- 仓库体积膨胀: 单个仓库会变得很大,
git clone
、git pull
时间变长。需要合理使用.gitignore
忽略构建产物等。Git LFS 可能用于大文件。 - 工具依赖性强: 高度依赖所选 Monorepo 工具链的正确配置和持续维护。
- 权限管理: 单一仓库下控制不同团队或个人对不同部分(apps/packages)的访问权限可能需要额外的 Git 配置或上层权限系统(如 GitLab Groups/Permissions)。
- 构建和测试规模: 如果每次提交都触发整个仓库的构建测试会非常慢。需要工具(Nx, Turborepo)提供智能的任务调度(只运行受影响的部分)和强大的缓存机制(本地+远程缓存 CI)。
总结
前端 Monorepo 是管理现代复杂前端项目架构的强大模式 ,特别适用于存在多个应用和共享组件库、追求统一高效开发和标准化 的场景。它能大幅提升代码复用度、开发协作效率以及一致性,但也带来了仓库管理和工具链的复杂度的提升。
在选择是否采用 Monorepo 时,应仔细评估项目的规模、团队结构、长期演进需求以及对工具链的学习和运维成本投入。对于中小型项目或没有强烈共享需求的项目,Multirepo 可能仍然是更简单的选择。但对于面临前述痛点(尤其是共享代码困难、标准化不一致、多个应用协作)的中大型前端项目,Monorepo 往往是极具价值的解决方案 。主流工具(特别是 PNPM Workspaces , Turborepo 和 Nx)的发展极大地降低了 Monorepo 的门槛并提升了开发体验。
Monorepo 和 Vite 的 vite-plugin-federation
(模块联邦) 不仅可以关联,而且在实际微前端架构中常常是互补的最佳实践组合。以下是它们之间的关联和协同工作方式:
🔗 关联点 1: 微前端的理想开发载体
-
vite-plugin-federation
解决的问题: 实现应用级 或组件级 的运行时动态加载和共享,让多个独立构建部署的微前端应用可以在浏览器中像单一应用一样协同工作。 -
Monorepo 解决的问题: 提供统一、高效的本地开发调试环境,管理多个微应用、共享库(组件、工具函数、配置)以及它们之间的依赖关系。
-
结合优势:
- 在 Monorepo 中,你可以将每个独立的微前端应用 放在
apps/
目录下(如app-home
,app-checkout
,app-admin
)。 - 将需要跨应用共享的组件、工具或状态管理库 放在
packages/
目录下(如shared-ui-components
,shared-utils
,shared-state
)。 - 使用
vite-plugin-federation
配置每个微应用导出的模块 (exposes
) 和需要从其他微应用(或远程)导入的模块 (remotes
)。 - 在 Monorepo 中,
shared-*
包可以通过 workspace:*
被多个微应用直接引用 (开发时是最新代码),同时这些共享包也可以通过vite-plugin-federation
暴露给 其他仓库 的微应用使用(如果架构允许)。 - 核心价值: 开发阶段 (Monorepo): 所有代码在一起,修改共享库或微应用,其他依赖方立即感知,调试效率极高。生产部署 (
vite-plugin-federation
): 各个微应用独立构建、独立部署、独立更新。
- 在 Monorepo 中,你可以将每个独立的微前端应用 放在
📂 目录结构示例 (Monorepo + Vite MF)
lua
my-microfrontend-monorepo/
├── apps/
│ ├── app-home/ # 主应用 (Vite + 模块联邦 Host)
│ │ ├── vite.config.ts # 配置 remotes: ['app-header', 'app-footer']
│ │ ├── src/
│ │ └── package.json # dependencies: {"@my/shared-ui": "workspace:*", ...}
│ │
│ ├── app-header/ # 头部导航微应用 (Vite + 模块联邦 Remote)
│ │ ├── vite.config.ts # 配置 exposes: { './Header': './src/Header.tsx' }
│ │ ├── src/
│ │ └── package.json
│ │
│ ├── app-footer/ # 底部信息微应用 (Vite + 模块联邦 Remote)
│ │ ├── vite.config.ts # 配置 exposes: { './Footer': './src/Footer.tsx' }
│ │ ├── src/
│ │ └── package.json
│ │
│ └── app-dashboard/ # 另一个独立的微应用 (可选 Host or Remote)
│ ├── vite.config.ts
│ ├── src/
│ └── package.json
│
├── packages/
│ ├── shared-ui/ # 共享的 UI 组件库 (被多个 apps 通过 workspace:* 引用)
│ │ ├── src/
│ │ │ ├── Button.tsx
│ │ │ └── ...
│ │ └── package.json
│ │
│ ├── shared-utils/ # 共享工具函数
│ │ ├── src/
│ │ └── package.json
│ │
│ └── shared-types/ # 共享的 TypeScript 类型定义
│ └── package.json
│
├── package.json # 根 package.json (pnpm workspace 配置)
└── pnpm-workspace.yaml # pnpm workspaces: ['apps/*', 'packages/*']
🔗 关联点 2:解决开发体验痛点
-
传统 Multirepo + MF 的痛点:
- 修改
shared-ui
组件库需要npm publish
(或使用npm link/yarn link
) 后才能在app-home
和app-header
中看到效果,流程繁琐。 - 调试跨多个仓库的改动非常困难。
- 修改
-
Monorepo + MF 的优势:
- 实时热更新: 修改
packages/shared-ui/Button.tsx
->app-home
和app-header
自动重新加载,无需发布或手动链接。 - 原子提交/PR: 如果修改了
shared-ui
和同时需要修改的app-header
,可以在同一个 Commit/PR 中完成并测试。 - 统一 CI/CD: 可以配置 Monorepo 工具链 (
Nx
,Turborepo
) 只构建和测试受影响的微应用,并触发对应的独立部署。
- 实时热更新: 修改
🔗 关联点 3:共享依赖管理优化
-
场景:
app-home
,app-header
都用了react
,react-dom
和@my/shared-ui
。 -
传统 MF (Multirepo):
- 每个微应用独立安装这些依赖,可能导致版本细微差异(如果没严格锁定)。
- 浏览器运行时可能加载多个版本的公共库(即使模块联邦支持共享依赖,配置管理较复杂)。
-
Monorepo + MF +
vite-plugin-federation
:-
根级依赖提升: Monorepo 的 workspaces (
pnpm
,yarn
,npm
) 会将react
,react-dom
提升到根node_modules
,所有微应用使用相同的物理依赖实例。 -
共享库内置:
@my/shared-ui
通过workspace:*
被直接引用。在生产构建时,vite-plugin-federation
可以将此库自动识别为共享依赖 (shared
) 并确保它在运行时只加载一次。你可以在vite.config.js
中配置shared
选项:
javascript// 在 app-home 的 vite.config.js 中 import federation from '@originjs/vite-plugin-federation'; export default { plugins: [ federation({ name: 'home-app', remotes: {...}, shared: ['react', 'react-dom', 'react-router-dom', '@my/shared-ui'] // 显式声明共享 }) ] }
-
效果: 最大程度减少重复代码和运行时冲突风险,优化应用加载性能。
-
⚠️ 注意事项与最佳实践
-
明确范围:
- Monorepo 内共享 (
packages/*
): 优先使用 workspace:*
依赖,用于开发阶段的即时共享。最终这些库可以被打包进微应用或用vite-plugin-federation
配置为shared
。 - 跨仓库/外部应用共享:
vite-plugin-federation
的exposes
/remotes
用于解决生产环境独立部署的微应用间的运行时共享。packages/*
也可以暴露给外部,但通常生产共享通过发布到私有 npm 或 CDN 更好。
- Monorepo 内共享 (
-
生产部署策略:
packages/*
中的库是否需要独立发布到 npm 私有仓库?如果是,workspace:*
需替换为发布的版本号 (可通过changeset
或lerna version
管理)。- 或直接打包进微应用?那么
vite-plugin-federation
的shared
配置就至关重要。
-
利用 Monorepo 工具优化构建: (
Nx
,Turborepo
)- 任务调度与缓存: 只构建/测试受代码变更影响的微应用/库。
- 远程缓存 (Remote Caching): 极大加速 CI/CD 流程。
-
版本一致性: Monorepo 更容易保证所有微应用使用相同的核心依赖版本 (React, Vue)。
✅ 总结:强强联合
- Monorepo 是管理前端微应用、共享库和统一开发体验的 代码组织和协作基石。
-
vite-plugin-federation
是实现微前端应用运行时独立部署、动态加载、模块共享 的 核心技术。
它们结合使用,能同时获得:
- 卓越的开发体验: 即时本地调试、跨应用修改原子性、统一工具链。
- 高效的生产架构: 独立部署、增量更新、依赖共享优化、应用组合灵活。
全面整合 Monorepo 架构与 Vite 模块联邦(vite-plugin-federation
) 的可视化示意图,重点突出 核心共享包、配置复用、依赖关系和运行时模块联邦交互:
markdown
___________________________________________________________________________________________
| Company Monorepo (Git Repo) |
|__________________________________________________________________________________________|
| |
| ┌──────────────────────┐ ┌───────────────────────┐ ┌─────────────────────┐ |
| │ Central Configs │ │ Core Packages │ │ Shared Libs │ |
| │ (All Projects Inherit) │◄─────┤ (Framework Agnostic) ├─────►│ (Business UI/Logic) │ |
| ├──────────────────────┤ ├───────────────────────┤ ├─────────────────────┤ |
| │ - @company/eslint │ │ - @company/foundation │ │ - @company/ui-core │ |
| │ - @company/tsconfig │ │ (HTTP, Auth, Logger)│ │ - @company/ui-forms │ |
| │ - @company/vite-preset│ │ - @company/design-tokens│ │ - @company/data-models│ |
| │ - @company/jest │ │ - @company/icons │ └─────────────────────┘ |
| └──────────────────────┘ └───────────────────────┘ ▲ |
| ▲ ▲ │ |
| │ │ │ |
|_________│__________________________________│______________________________│______________|
│ │ │
│ Development Phase │ │
│ (Workspace:* Links + Hot Reload) │ │
│ │ │
▾│ ▾│ ▾│
___________________________________________________________________________________________
| Applications Layer |
|_________________________________________________________________________________________|
| |
| ┌─────────────────────────────────────────────────────────────────────────────────────┐|
| │ Module Federation Host (Main Portal) │|
| │ (http://portal.company.com) │|
| ├─────────────────────────────────────────────────────────────────────────────────────┤|
| │ vite.config.js: │|
| │ remotes: { │|
| │ 'app-header': 'https://assets.com/app-header/remoteEntry.js', ◄──────────────────┼──┐
| │ 'app-dashboard': 'https://assets.com/app-dashboard/remoteEntry.js' │ │
| │ }, │ │
| │ shared: [ **关键共享依赖** ] │ │
| │ 'react', 'react-dom', '@company/foundation', '@company/ui-core' │ │
| └───────────────────────────────────────────┬──────────────────────────────────────────┘ │
| │ 运行时动态加载 (Runtime Dynamic Loading) │
|┌─────────────────────┬─────────────────────┬─┴───────┬─────────────────────┬─────────────┐|
|| App Header (MF) │ Dashboard (MF) │ │ Admin Console │ Marketing │|
|| (Remote Component) │ (Remote Module) │ │ (Standalone App) │ Website │|
||├───────────────────┐│├───────────────────┐│ ├─────────────────────┼─────────────┤|
||│ vite.config.js: │││ vite.config.js: ││ │ Uses: │ Static Site │|
||│ name: 'app-header'│││ name: 'app-dash' ││ │ - @company/foundation │ │|
||│ exposes: { │││ exposes: { ││ │ - @company/ui-core │ │|
||│ './Header':...│││ './Chart': ...││ │ - @company/icons │ │|
||│ }, │││ } ││ └─────────────────────┘ │|
||│ shared: [ │││ shared: [ ││ │|
||│ 'react', '@company/ui-core' ◄────────┼─────┐ │|
||│ ] │││ ] ││ │ │|
||└───────────────────┘│└───────────────────┘│ │ │|
|| │ │ │ │|
|| Production: │ Production: │ │ │|
|| https://assets.com/ │ https://assets.com/ │ │ │|
|| app-header/ │ app-dashboard/ │ │ │|
|└──────────────────────┴──────────────────────┘ │ │|
| │ │|
|◄────────────────── Shared Dependency Pool ────────────────────────────────────────────────►|
| (Runtime Singleton Guaranteed by Module Federation's shared: [...] config) |
| |
|_________________________________________________________________________________________|
🔑 关键机制解读:
-
Monorepo 基础架构 (开发阶段)
-
Central Configs
: 所有应用和库继承统一的工具链配置(ESLint/TSConfig/Vite 等) -
Core Packages
:@company/foundation
提供 HTTP/Auth/Logger 等跨应用核心能力@company/design-tokens
和@company/icons
被 UI 库消费
-
Shared Libs
:@company/ui-core
实现共享 UI 组件(依赖 design-tokens)@company/data-models
定义全栈数据类型
-
依赖链接 : 所有内部包通过
workspace:*
协议即时引用最新代码
-
-
模块联邦运行时 (生产阶段)
-
Host (Main Portal)
- 配置
remotes
指向各微应用的remoteEntry.js
-
shared: [...]
声明关键共享依赖(React/Foundation/UI-Core),确保运行时单例
- 配置
-
Remote (App Header/Dashboard)
- 通过
exposes
暴露自身组件 - 同步 Host 的
shared
依赖 (如@company/ui-core
),避免重复加载
- 通过
-
动态加载机制:
javascript// Host 动态加载 Remote 组件 const Header = React.lazy(() => import("app-header/Header"));
-
-
依赖共享控制
- 开发阶段 : 通过 PNPM Workspaces 在根
node_modules
提升公共依赖 - 构建阶段 : Vite 根据
shared
配置标记共享模块 - 运行阶段 : 模块联邦加载器确保
shared
模块全局单例
- 开发阶段 : 通过 PNPM Workspaces 在根
-
独立应用协作
- Admin Console :虽在 Monorepo 中,但作为独立应用构建部署(仍共享基础包)
- Marketing Website:可独立技术栈(如 VitePress)
⚡ 性能优化点:
-
智能构建 (Turborepo)
- 只构建受代码变更影响的应用/库
- 本地 + CI 远程缓存加速构建
-
运行时依赖优化
php// vite.config.js (优化示例) federation({ shared: { // 按需加载共享包 'lodash': { eager: false }, // 预加载基础框架 '@company/foundation': { eager: true } } })
-
按需暴露 Remote 模块
cssexposes: { // 细粒度暴露,减少 entry 体积 './Header': './src/components/Header.tsx', './Footer': './src/components/Footer.tsx' }
🌐 部署拓扑示例:
scss
CDN
(assets.company.com)
/ | \
┌─────/ | \──────┐
│ / │ \ │
▾│ ▾ ▾│ ▾│ ▾│
┌────────────┐ ┌────────────┐ ┌────────────┐
│ App Header │ │ App Dash │ │ UI-Core Lib│
│ (MF Remote)│ │ (MF Remote) │ │ (Shared Lib) │
└──────┬─────┘ └──────┬─────┘ └──────┬─────┘
│ │ │
└──────┐ ┌────┘ │
│ │ │
┌──┴─────┴───┐ │
│ Main Portal ├─────────────────┘
│ (MF Host) │
└──────┬──────┘
│
▾
https://portal.company.com
此架构同时实现了:
✅ 开发效率 :Monorepo + Workspace 协议下的热更新
✅ 复用一致性 :通过核心包强制统一技术底座
✅ 部署独立性 :模块联邦实现微应用独立构建部署
✅ 运行时性能:共享依赖单例加载 + 按需加载