引言:前端架构演进与挑战
区别传统的静态网站,现在的各种 Web
应用被称为富互联网应用。在线服务的激增使我们能够方便地观看喜欢的电影和直播、即时订购外卖以及各种生活便利。
然而这样的技术实现往往会把功能都集中在一个项目当中,随着模块越来越多,这种「单体应用」就面临了许多难题:
-
多人协作困难:多个开发团队在同一个代码仓库中协作,容易产生代码冲突、依赖冲突。
-
代码复杂度高:项目膨胀,维护成本上升,回归测试压力变大。
-
版本升级困难:一个模块的小变动可能影响整个应用,发布频率受到限制。
为了解决这样的问题,后端提出了「微服务架构」的解决方案。而在前端,同样演进出了对应的方向------微前端。
一、什么是微前端?
1.1 微前端的定义
微前端是受微服务启发的一种新兴架构。它背后的主要思想是将一个单体代码库分解成多个较小的部分,以便多个相对独立的团队进行分工协作,实现了复杂业务解耦 、独立部署 、团队自治 。不仅适用于 monorepo
,也适用于 polyrepo
。
1.2 微前端的发展背景
微前端并不是一开始就存在的,而是伴随以下几个变化逐步发展出来的:
- 公司业务越来越复杂,单一前端团队无法高效支撑;
- 项目重构或多个产品线需要共存,但技术栈不统一;
- 希望多个子系统可以独立部署、独立升级;
- 前后端分离普及后,前端层也需要更细的拆分和治理。
1.3 适合微前端的业务类型
适合场景 | 说明 |
---|---|
多产品线并存的后台管理系统 | 每个产品线可作为子应用独立开发和部署 |
技术栈混用(React、Vue、Angular) | 允许不同技术栈共存 |
渐进式重构旧系统 | 可逐步替换旧模块为新微前端模块 |
多团队协作开发大型项目 | 团队边界清晰,职责明确 |
1.4 应用微前端
在应用微前端之前需要考虑以下因素:
- 业务领域描述
- 自治代码库
- 独立部署
- 单一团队负责
在确定应用微前端架构以后,需要确定如何从技术视角考虑微前端,并且需要决定是在同一个视图中集成多个微前端,还是每个视图中集成一个微前端,即如图所示横向拆分和纵向拆分。

在横向拆分方案中,同一个视图上会有多个微前端。在出现以下几种情况时效果比较好:
- 当子业务在多个视图中渲染时,子业务的复用性成为业务关键
- 当SEO时项目的必选项,需要使用服务端渲染时
- 当前端项目至少几十人协同开发,不得不把项目拆分成多个子域
- 当面临一个定制化的多租户项目时
而在纵向拆分方案中,每个团队负责一个业务领域。当项目需要一致的用户界面变化和跨页面的流畅的用户体验时,纵向拆分显得非常有用。对于 SPA 来说,纵向拆分方式的开发体验最为契合。纵向拆分中 App shell 利用全局路由来加载不同的微前端。

下图显示传统的微服务架构,其前端整体结构使用 API 网关连接到后端微服务。

下图显示了具有不同微服务实现方式的微前端架构。

1.5 微前端实践原则
Sam Newman在《微服务设计》中强调了一些微服务的原则,看看如何应用到微前端。
- 围绕业务领域建模:弄清如何分治应用有利于后期添加新功能
- 自动化文化:确保稳固的持续集成、流水线部署以及快速反馈循环
- 隐藏实现细节:每个团队不需要依赖外部,专注于内部的实现细节
- 分布式治理:分散团队的决策权,在特定领域之内的操作不需要等待领导决策
- 独立部署:每个团队按照自己的计划独立部署应用
- 故障隔离:必须提供替代的内容或者隐藏应用的对应部分
- 高度可观察性:前端监控变得日益重要,投入资源准备随时解决故障而非完全预防故障
二、微前端核心原理
2.1 主子应用的架构模型
微前端架构采用一种类似"门户 + 插件"的结构,将整个页面按照职责边界划分成主应用和多个子应用。
-
主应用(Host App / Shell)
-
负责整体框架结构的搭建,包括:
- 全局路由管理
- 公共组件(导航栏、菜单、权限控制等)
- 子应用的注册、加载、卸载
- 应用间通信调度器
-
-
子应用(Sub App / Micro App)
-
每个子应用是一个独立的 SPA 或 MPA,可以:
- 拥有自己的路由体系
- 使用独立的技术栈(React/Vue/Angular)
- 独立构建、测试和部署
- 在运行时被主应用动态挂载
-
一个类比:
可以把主应用看作"容器",子应用看作"插件模块"。主应用控制"何时加载哪个模块",而模块本身专注于自己的逻辑实现。
2.2 核心技术原理
微前端架构的最大魔力在于:它让多个独立开发、构建、部署的前端项目,看起来像是一个统一的网页应用。用户完全感知不到页面是在多个代码库之间跳转,开发者也可以实现子应用的独立演进。
那么,从技术上来说,微前端是怎么把一个子应用"嵌入"主应用中的呢?
2.2.1 子应用的基本状态:本质是一个远程资源包
从主应用角度看,每一个子应用就是一个远程构建好的静态资源包,可能部署在如下路径:
js
https://static.example.com/sub-app-user/
├── index.html
├── main.js
├── styles.css
这个资源包含了子应用的HTML模板、JS入口文件、CSS样式文件。
2.2.2 主应用挂载子应用的流程
主应用并不会将子应用打包进来,而是通过配置动态加载远程子应用,过程大致如下:
步骤1:注册子应用
在主应用中注册子应用的信息:
ts
registerMicroApps([
{
name: 'userApp',
// 子应用的资源入口
entry: 'https://static.example.com/sub-app-user/',
// 渲染子应用的 DOM 容器
container: '#subapp-viewport',
// 子应用激活的路由规则
activeRule: '/user',
}
]);
步骤2:当路由命中时,主应用动态加载子应用资源
主应用拦截到当前路由为 /user
后,会执行如下操作:
- 通过
fetch
或iframe
等方式加载子应用入口页面(如index.html
) - 解析该 HTML 文件中需要加载的 JS、CSS
- 插入
<script>
和<link>
标签,将子应用的资源动态注入主应用页面中 - 查找子应用打包暴露的全局对象(如
window['userApp']
)或模块导出,执行其mount()
函数
步骤3:主应用调用子应用的 mount()
,渲染子应用
一旦子应用的 JS 加载完毕,就会调用其生命周期:
js
window['userApp'].mount({
container: document.querySelector('#subapp-viewport'),
props: { fromMainApp: true }
});
此时:
- 子应用会将自己的路由系统、组件、页面渲染到主应用提供的
container
中 - 子应用像一个"沙箱应用"一样运行在主页面里
步骤4:切换路由时调用 unmount()
当用户跳转到另一个子应用(如 /order
)时,主应用会调用当前子应用的 unmount()
方法,做清理工作(如移除事件监听、清空 DOM 节点等),然后加载并挂载新的子应用。
2.2.3 从用户视角看:为何"无感知"?
这套机制之所以能实现"用户无感"的体验,核心在于:
- 页面不刷新,子应用是局部加载并渲染到主页面中的
- 主应用统一管理路由、导航栏等公共区域,切换时不丢失上下文
- 各个子应用在同一个 URL 路径规则下工作,地址栏保持统一
- 主子应用共享样式、组件、状态(如通过主应用传递 props)
因此,从用户视角来看,整个网页就像是一个完整的一体化系统,但背后其实是多个不同项目在协作运行。
2.3 微前端集成方案
微前端的核心目标是让多个独立前端项目协同工作 ,而"集成方案"指的就是:主应用如何加载、渲染并控制子应用的运行。
2.3.1 iframe集成
原理 :主应用通过 iframe
加载子应用的页面,每个子应用运行在自己的浏览器上下文中。
js
<iframe src="https://sub-app.example.com" />
2.3.2 运行时HTML插入+JS挂载
原理:
- 主应用在运行时,通过 AJAX 或
<script>
加载子应用的资源(HTML/JS/CSS); - 将子应用渲染到主应用指定容器;
- 调用子应用暴露的生命周期函数:
bootstrap → mount → unmount
js
registerMicroApps([
{
name: 'orderApp',
entry: 'https://order.example.com/',
container: '#subapp-container',
activeRule: '/order',
},
]);
2.3.3 Webpack Module Federation(构建时集成)
原理:
- 在构建阶段声明共享模块(remote、exposes);
- 主应用可以像本地模块一样引入子应用暴露的内容;
- 支持模块按需加载,避免冗余依赖
js
// 主应用 Webpack config
remotes: {
userApp: 'userApp@https://cdn.example.com/remoteEntry.js'
}
2.3.4 基于 Web Components
Web Components 是浏览器原生支持的一组规范,包括:
Custom Elements
:自定义标签,如<user-app></user-app>
Shadow DOM
:为组件提供样式和 DOM 隔离HTML Templates
:定义可复用的 HTML 结构
在微前端中,我们可以将每个子应用封装成一个 Web Component,然后在主应用中直接使用自定义标签进行挂载。
js
<script src="https://cdn.example.com/user-app/main.js"></script>
<user-app></user-app>
2.4 总结
实现方式 | 集成时机 | 是否支持异构 | 隔离性 | 性能 | 通信复杂度 | 实现复杂度 |
---|---|---|---|---|---|---|
iframe | 运行时 | ✅ | ⭐⭐⭐⭐⭐(进程级) | ❌ 慢 | ⭐⭐⭐⭐(需 postMessage) | ⭐(非常简单) |
HTML 插入 + JS 挂载 | 运行时 | ✅ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐(eventBus/props) | ⭐⭐⭐⭐ |
Webpack Module Federation | 构建时 | ❌(需统一工具链) | ⭐⭐(无沙箱) | ⭐⭐⭐⭐⭐(最佳) | ⭐(共享模块) | ⭐⭐⭐⭐⭐ |
Web Components | 运行时 | ✅(原生支持) | ⭐⭐⭐⭐⭐(Shadow DOM) | ⭐⭐⭐⭐ | ⭐⭐(自定义事件/props) | ⭐⭐(需封装生命周期) |
三、主流微前端框架对比
目前,微前端领域已涌现出多种实现方案和框架。以下介绍四种具有代表性的微前端框架,它们代表了不同的实现范式 和适用场景。
3.1 Single-SPA
3.1.1 框架发展历程
Single-SPA 是最早定义"微前端"形态的框架之一,由 Canopy 公司在 2016 年开源,首次将主-子应用模型抽象为标准化的生命周期机制,并且允许不同技术栈的子应用共存(React、Vue、Angular 等)。
该框架目前已进入稳定维护期,是许多微前端框架的理论基础(包括 qiankun、wujie)。
3.1.2 实现原理概述
Single-SPA 并不负责子应用资源加载,而是提供运行时框架与生命周期调度机制:
- 统一注册子应用信息(基于路由)
- 在路由切换时执行子应用的
bootstrap → mount → unmount
- 通过
SystemJS
或开发者自定义方式加载子应用 JS 入口 - 不强制样式隔离、沙箱机制,需自行集成
3.1.3 优点
- 技术中立:支持多技术栈共存(React/Vue/Angular)
- 生命周期清晰:微前端应用运行流程全流程掌控
- 社区成熟:作为微前端概念提出者,架构思想广泛应用
- 插件化强:与 SystemJS 等组合更灵活
3.1.4 缺点
- 较低层:需要自己处理资源加载、样式隔离、通信机制
- 学习成本略高,开发体验不如 qiankun 等"全家桶"
- 子应用需主动适配生命周期(非零侵入)
3.2 qiankun
3.2.1 框架发展历程
qiankun 是由阿里巴巴旗下 Ant Financial 团队于 2019 年开源,构建于 Single-SPA 之上,但进一步实现了运行时资源加载、样式隔离、沙箱机制、通信机制等一整套完整解决方案,被誉为"企业级微前端最佳实践"。
目前在国内外都有广泛使用(如阿里云、钉钉、支付宝)。
3.2.2 实现原理概述
qiankun 的核心技术架构:
- 构建于 single-spa 之上(生命周期调度)
- 使用 HTML Entry 加载子应用资源(HTML + JS + CSS)
- 使用 沙箱(Proxy + Snapshot) 实现全局变量隔离
- 使用 CSS Scope + strict style isolation 处理样式冲突
- 提供
initGlobalState()
等通信机制(基于发布-订阅)
主应用注册子应用示例:
ts
registerMicroApps([
{
name: 'userApp',
entry: 'https://cdn.xxx.com/user/',
container: '#container',
activeRule: '/user',
}
]);
3.2.3 优点
- 开箱即用:涵盖资源加载、生命周期、样式隔离、通信等
- 兼容技术栈:支持 Vue、React、Angular、纯 HTML
- 开发体验好:主子应用接入成本低,文档完善
- 支持 prefetch 预加载机制
3.2.4 缺点
- 内部实现复杂(调试较困难)
- 非全局沙箱(不适合高安全要求的系统)
- 不适合 SSR 场景(浏览器为核心)
3.3 wujie
3.3.1 框架发展历程
Wujie 是腾讯开源的一款轻量级微前端框架,诞生于 2022 年,目标是解决 qiankun 在性能、安全、加载机制方面的部分痛点。
Wujie 使用原生 iframe 嵌套 +动态补丁挂载方式,实现近乎原生性能的微前端架构。
3.3.2 实现原理概述
- 每个子应用通过 iframe 承载(避免全局变量污染)
- 使用原生浏览器机制进行沙箱和样式隔离(借助 Shadow DOM)
- 启动阶段将子应用 DOM 迁移到主页面中(DOM Patch)
- 提供主子通信、生命周期调度能力
Wujie 使用示例:
ts
<wujie-vue
name="user"
url="https://user-app.cdn.com"
sync
alive
></wujie-vue>
3.3.3 优点
- 高性能:相比 qiankun 启动更快(DOM patch 优化)
- 真正隔离:基于 iframe,避免全局污染
- 轻量实现:不依赖第三方调度框架
- 支持 keep-alive、DOM 缓存
3.3.4 缺点
- 运行机制复杂,调试门槛略高
- 使用 iframe 带来部分兼容性风险
- 缺少 qiankun 社区活跃度
3.4 module-federation
3.4.1 框架发展历程
Webpack Module Federation 是 Webpack 5 在 2020 年引入的新特性,支持多个独立构建的项目共享模块、组件、逻辑,实现构建时的微前端。
它并不是微前端框架,但被广泛应用于构建类 monorepo 的大型项目中。
3.4.2 实现原理概述
- 每个子应用通过 Webpack 配置
exposes
和remotes
- 主应用在运行时加载远程模块(不再是 HTML,而是 JS Module)
- 自动管理共享依赖(如 React、Vue),避免重复打包
js
// 主应用
remotes: {
userApp: 'userApp@https://cdn.example.com/remoteEntry.js'
}
子应用暴露模块:
js
exposes: {
'./UserPage': './src/pages/UserPage.vue',
}
3.4.3 优点
- 性能极佳:构建时优化,打包依赖最小
- 模块级复用:可共享组件、hook、工具库等
- 自动依赖去重:支持 singleton 配置
3.4.4 缺点
- 仅适用于 Webpack 5(Vite、Rollup 不支持)
- 配置复杂,调试成本高
- 不适用于技术栈异构或运行时动态加载场景
- 不提供生命周期、沙箱、通信机制(需自行实现)
四、微前端常见挑战
虽然微前端架构在工程上带来了灵活性与模块化,但也引入了许多"从单体应用中从未遇到"的复杂问题。
4.1 微前端的组合
微前端架构下,每个子应用由独立团队开发、部署,最终需要在主应用中"拼接"为一个整体用户体验。这个过程就是"组合"(Composition)。
- 如何定义主应用与子应用的分工边界?
- 子应用如何以模块化方式挂载?
- 如何避免主子应用之间强耦合?
常见解决方案
- 统一规范接口 :主应用通过配置(如
name
、entry
、container
、activeRule
)管理子应用挂载 - 生命周期抽象 :采用 single-spa、qiankun 等框架定义
bootstrap
、mount
、unmount
- 可视化组合平台:部分大厂通过后台平台配置哪些子应用加载到哪些容器
4.2 微前端的路由
传统 SPA 由一个框架控制整个路由系统,而微前端场景中,主子应用都需要路由,各自有自己的页面、跳转逻辑。
- 主子应用路由如何解耦?
- 子应用如何感知当前 URL?
- 如何避免路由冲突或丢失?
常见解决方案
- 嵌套路由机制 :主应用控制整体路由前缀(如
/user/*
),子应用控制自身内部路由 - hash 路由隔离 :主、子应用分别使用
history
和hash
路由(避免路由冲突) - 统一监听机制:通过主应用统一监听 URL 变化并通知子应用(如 qiankun 自动处理)
4.3 微前端的状态管理
当用户跨子应用跳转(例如从"订单模块"跳转到"个人中心"),有些状态是全局共享的,比如登录信息、主题设置、语言等。
- 状态在哪一层维护?主应用?子应用?
- 子应用之间如何共享状态?
- 如何避免状态污染或丢失?
常见解决方案
- 主应用持有全局状态:如登录态、权限信息,由主应用下发
- 通过通信桥接共享状态 :例如 qiankun 的
initGlobalState
提供了响应式共享状态 - 封装状态管理插件 :如使用
redux-subspace
、zustand context bridge
等专门适配微前端的方案
4.4 微前端之间的通信
微前端系统中,多个子应用由不同团队维护,需要在运行时进行事件通知或数据交互。例如,商品模块通知购物车模块"商品已加入"。
- 主子、子子通信通道如何建立?
- 事件如何订阅/解绑?生命周期如何管理?
- 通信协议是否标准化?
常见解决方案
- 事件总线机制 :主应用提供全局 EventBus(可封装在
window
或 shared module) - 框架自带通信系统 :如 qiankun 的
initGlobalState
提供发布-订阅模型 - 使用浏览器原生通信机制 :如
CustomEvent
、window.postMessage
(iframe 场景)
4.5 微前端之间的样式隔离
多个子应用渲染到同一页面中时,CSS 极易发生污染,比如全局样式冲突、类名重叠、第三方组件样式覆盖等。
- 子应用样式是否会污染主应用?
- 如何防止多个子应用样式互相干扰?
- 如何保证主题风格一致的同时避免全局污染?
常见解决方案
- 命名空间隔离:使用 CSS Modules、BEM、Scoped CSS 避免类名冲突
- Shadow DOM:Web Components / Wujie 默认支持样式隔离
- 运行时样式处理 :如 qiankun 提供
strictStyleIsolation
或scopedCSS
配置,将样式作用域限定在容器内
参考资料
- AWS规范性指导-了解和实现微前端
- 《微前端设计与实现》------卢卡 梅扎利拉
- 领域驱动设计------Eric Evans