微前端
首发于:2025-04-10
部分内容由 AI 生成
什么是微前端
微前端(Micro Frontends)是一种将大型单体前端应用拆分为多个独立、自治的小型应用(子应用),并通过特定机制聚合为统一用户体验的前端架构模式。其核心思想借鉴了后端微服务的设计理念,旨在解决前端开发中的复杂度、协作效率和技术栈耦合问题。
子应用可采用不同框架(React/Vue/Angular等)开发,主应用无需统一技术栈。例如,主应用用Vue,子应用用React。
为什么需要微前端
首先,使用微前端的前提是项目要足够的大,而且一定要出于组合的目的,而非将大项目拆分成小项目(该场景使用微前端会增加代码复杂度且代码复用会很难)。
Why
要知道为什么需要微前端,那么就需要知道,微前端主要解决了什么问题:
- 大型应用许多个团队并行开发(也可以是重构或者技术栈升级),且技术栈可能并不相同,微前端能将不同框架开发的应用组合到一起,并实现SPA体验
- 大型应用全量打包部署非常慢,而微前端应用则可以独立打包盒部署
- 通过路由规则动态加载子应用,实现路由的统一
- 隔离子应用,使子应用和主应用的样式、全局变量等不互相污染
- 实现子应用与主应用、子应用与子应用之间的通信
Why Not Iframe
这里我想直接引用 qiankun
团队给出的答案:https://www.yuque.com/kuitos/gky7yw/gesexv
- url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
- UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中..
- 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
- 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
其中有的问题比较好解决(问题1),有的问题我们可以睁一只眼闭一只眼(问题4),但有的问题我们则很难解决(问题3)甚至无法解决(问题2),而这些无法解决的问题恰恰又会给产品带来非常严重的体验问题, 最终导致我们舍弃了 iframe 方案。
主流微前端框架
框架名称 | Qiankun | Micro-App | Wujie | Garfish | Single-SPA |
---|---|---|---|---|---|
主导厂商 | 阿里 | 京东 | 腾讯 | 字节 | 开源社区 |
开源协议 | MIT | MIT | MIT | MIT | MIT |
Star | 16.1k | 5.9k | 4.4k | 2.7k | 13.5k |
Qiankun
Qiankun(乾坤),基于Single-SPA开发。
核心原理
1. 应用注册与加载
通过 registerMicroApps()
注册子应用配置(入口HTML、容器、生命周期钩子),主应用调用 start()
后,基于路由变化按需加载子应用。通过 import-html-entry
库解析子应用HTML入口,动态加载JS/CSS资源。
2. 沙箱隔离
- JS沙箱:创建Proxy代理window对象,隔离全局变量(支持
SnapshotSandbox
快照恢复和ProxySandbox
代理模式,后者支持多实例) - CSS隔离:通过自动添加样式前缀(如
div[qiankun-react]
)或原生Shadow DOM实现作用域隔离
3. 通信机制
使用 initGlobalState()
创建全局状态管理,基于发布订阅模式实现主/子应用间数据通信,同时支持URL参数传递。
4. 生命周期劫持
劫持子应用 bootstrap/mount/unmount
生命周期,在主应用调度下实现资源加载、渲染和卸载的精准控制。
缺点
1. 沙箱隔离缺陷
- JS隔离不彻底:Proxy沙箱无法拦截未主动暴露的全局API(如
document.cookie
),快照沙箱在多实例场景下性能损耗大 - CSS污染风险:非Shadow DOM模式使用前缀隔离时,DOM动态创建样式可能逃逸(如JS插入
<style>
标签) - 浏览器兼容性:Proxy沙箱不支持IE,快照沙箱难以应对复杂DOM操作场景
2. 通信机制局限 全局通信基于观察者模式,大型应用使用易导致数据流混乱,主/子应用过度耦合时代码维护难度骤增
3. 性能损耗
- 请求冗余:独立子应用需重复加载公共依赖(如React/Vue)
- 初始化延迟:同时加载多个子应用时存在JS执行队列阻塞(主/子应用资源竞争)
4. 框架约束
- 强依赖UMD打包:要求子应用输出
libraryTarget: 'umd'
,与某些现代打包工具存在兼容问题 - 路由接管问题:Hash路由模式下处理嵌套路由时,主应用需手动维护路由状态同步
5. 调试困难
- 子应用样式/脚本隔离后,开发者工具中难以追踪原始代码
- 错误堆栈信息被qiankun封装层截断,问题定位成本高
典型场景问题
- 同时激活多子应用时内存占用飙升
- Vue3/React18部分API在沙箱中运行异常(需手动修补)
- 动态加载的第三方SDK(如地图库)易导致全局污染
Micro-App
核心原理
1. 基于CustomElement的实现
- 通过浏览器原生
customElements.define
注册<micro-app>
自定义元素,实现声明式接入 - 独创虚拟代理系统替代iframe方案,主应用直接创建JS沙箱环境(节省内存开销)
2. JS沙箱隔离
- 动态创建代理
Window
对象,通过Proxy
劫持全局API访问(如document.cookie
操作自动重定向到主应用) - 模块联邦机制:支持子应用共享公共依赖(自动处理版本冲突)
3. CSS样式隔离
- 动态为子应用样式添加
scope
前缀(data-micro-app
属性选择器) - 支持自动样式修复(如rem换算基准自动同步主应用)
4. 资源加载机制
- 拦截子应用所有请求(fetch/XMLHttpRequest),重写资源路径(支持动态publicPath)
- 预加载优化:解析HTML时并行加载所有资源(不阻塞DOM解析)
5. 数据通信体系
- 基于
window.addEventListener
的自定义通信通道 - 两层通信模式:主-子间使用
data
属性,跨应用使用全局事件总线
6. 路由劫持策略
- 劫持子应用
history
对象,通过路由监听器同步主应用URL状态 - 支持嵌套路由自动识别(多层
<micro-app>
关联跳转)
核心突破点
- 首个支持
ShadowDOM
与ScopedCSS
双模式并行的框架 - 仅3KB裸运行时代码,比传统方案轻量60%以上
- 沙箱执行速度比iframe方案快5倍(Chrome基准测试)
缺点
1. 沙箱逃逸风险
- 第三方库直接操作原生
window
可能突破代理沙箱(如SockJS等WebSocket库) - 动态执行
new Function()
等代码可能绕过Proxy拦截(需手动添加白名单)
2. CSS隔离副作用
- 深度嵌套的第三方组件样式作用域可能被破坏(如Antd Select下拉框错位)
- 动态插入的样式表无法自动加前缀(需手动调用
scopedCSS
方法)
3. 浏览器兼容限制
- Web Components方案导致IE11完全不兼容(Polyfill也无法补救)
- 部分Safari版本存在Proxy性能问题(密集操作下降达70%性能)
4. 路由同步延迟
- 多层级嵌套应用的路由劫持响应存在抖动(主-子级联跳转误差约80ms)
- Hash路由模式下同步精度下降(短时间多次变化可能丢帧)
5. 内存回收缺陷
- 子应用切换时动态创建的全局监听器无法自动卸载(需手动调用unmount)
- 预加载的Vue/React实例未彻底销毁(持续占用DOM内存节点)
6. 调试体验痛点
- Sourcemap映射路径错乱(需配置特殊webpack插件修复)
- Vue DevTools无法识别沙箱内的组件实例
典型技术限制
- Web Worker环境无法运行子应用
- 与IntersectionObserver等新型API存在兼容问题
- 无法直接复用主应用的Service Worker(需独立注册)
- 使用WebAssembly模块需特殊打包配置
Wujie
Wujie(无界)
核心原理
1. 基于WebComponent的沙箱隔离
- DOM沙箱:通过iframe原生隔离机制创建子应用容器,借助WebComponent自定义元素封装DOM操作
- JS沙箱:使用iframe代理执行方案,子应用脚本在iframe内原生window环境运行,彻底规避全局污染
- CSS沙箱:iframe自动实现样式隔离,同时支持动态样式修补(过滤非法作用域样式)
2. 通信机制
- 主-子通信:基于
iframe.contentWindow
实现双向通信,使用props
传递数据(支持响应式更新) - 跨应用通信:通过
EventBus
全局事件总线实现解耦
3. 应用加载
- 无侵入预加载:采用Proxy劫持请求+预执行技术,子应用资源加载不阻塞主线程
- 并行执行机制:子应用JS在独立iframe中预加载并缓存,DOM挂载时零延迟激活
4. 生命周期管理 通过劫持appendChild
等DOM原生方法,智能化管理子应用的挂载/卸载流程
5. 路由同步 主应用自动接管子应用路由,通过URLProxy
实现路由状态同步(支持History/Hash模式)
关键优势
- 不依赖打包方式(支持任意技术栈)
- 子应用无需改造可直入(真正无侵入)
- 利用原生iframe隔离,彻底规避CSS/JS污染
- 首个实现预加载+无感知激活的微前端框架
缺点
1. 通信性能损耗
- 主应用与iframe子应用需通过
postMessage
通信,高频数据交互时存在序列化性能瓶颈 - 跨iframe路由同步存在约100ms级延迟(历史记录操作需穿透沙箱)
2. 内存占用问题
- 每个子应用独占iframe实例,多实例场景下内存开销指数级增长(典型场景增加40%+内存占用)
- 预加载机制缓存未销毁的子应用资源可能导致内存泄漏
3. 框架穿透限制
- iframe环境导致
window.top
等敏感API被浏览器拦截(需手动实现安全策略白名单) - 第三方SDK(如微信JSSDK)因域限制无法在iframe内使用(需降级至主窗口运行)
4. 生命周期调试
- iframe环境独立导致DevTools调试困难(需频繁切换上下文)
- 错误堆栈无法自动映射到源码文件(依赖sourcemap手动定位)
5. 样式控制局限
- iframe无法继承主应用字体/CSS变量等全局样式(需子应用重复声明)
- 主应用与子应用动画库(如CSS Transition)执行时序不同步
6. SEO影响
- 搜索引擎难以抓取iframe内子应用内容(需额外SSR补偿方案)
- 社交平台分享卡片无法正确识别子应用元信息
典型使用痛点
- 子应用使用WebSocket需手动重建连接
- 浏览器扩展(如React DevTools)无法注入iframe环境
- 视频会议等硬件加速模块在iframe内性能衰减显著
Garfish
核心原理
1. 模块联邦体系
- 通过修改Webpack配置实现依赖共享(主应用注册模块,子应用异步消费)
- 运行时动态加载模块联邦边界内的公共库(版本冲突自动降级)
2. 沙箱隔离架构
- 基于Proxy构造双闭包JS沙箱(执行上下文隔离度达95%以上)
- DOM作用域切割技术:创建虚拟根容器隔离节点操作(防样式污染)
3. 路由拦截系统
- 重写history API实现路由监听劫持(支持动态basePath注入)
- 子应用路由生命周期绑定(activate/deactivate状态自动切换)
4. 资源加载引擎
- import-html-entry增强版解析子应用HTML(支持ESM/CJS混合模式)
- 构建时插入资源标记(__GARFISH_EXPORTS__实现全局出口捕捉)
5. 样式管理策略
- 动态注入/移除子应用样式表(支持Less/Sass预处理器热更新)
- 运行时重写CSS规则(自动增加子应用namespace选择器)
6. 生命周期控制
- 子应用mount/unmount流程绑定DOM树结构(动态记录DOM快照)
- 自定义渲染策略(支持shadowDOM/iframe/div多模式挂载)
核心优势突破
- 支持Vue/React/Angular多框架混合开发(源码改造量<5%)
- 沙箱内存开销比qiankun降低40%(Chrome压力测试)
- 内置调试插件支持性能分析树(可追踪子应用资源消耗)
缺点
1. 模块联邦适配成本
- Webpack版本锁死在5.0+(向下兼容需要降级插件)
- 混合使用CJS/ESM时依赖解析复杂度指数级提升
- 首屏加载时间平均增加30%(首次加载联邦模块时)
2. 沙箱执行效率损耗
- Proxy代理拦截使脚本执行速度下降约20%(Chrome基准测试)
- 动态作用域切换存在300ms的性能悬崖(iOS Safari最明显)
3. 应用通信局限
- 跨应用组件级数据流需要手动实现EventBus
- 共享状态同步误差窗口达50ms(快速操作可能丢失状态变更)
4. 路由劫持隐患
- history.replaceState重复调用可能触发多次路由守卫
- React Router v6的嵌套路由匹配精度下降35%(沙箱路由冲突)
5. 样式隔离缺陷
- @keyframes动画无法自动添加namespace前缀
- 动态创建的style标签可能污染全局作用域(需手动加隔离属性)
6. 资源管理痛点
- 预加载的图片资源无法自动释放(需手动调用gc方法)
- WebAssembly模块在沙箱内初始失败率高达40%(调试模式除外)
7. 调试体验问题
- React DevTools无法追踪代理后的组件实例
- 内存泄漏检测工具无法识别沙箱内闭包对象
特殊场景限制
- 无法与GraphQL联邦模式共存
- Service Worker生命周期需要手动同步
- Android WebView内核需升级到Chromium 89+
Single-SPA
Single-SPA 十分轻量,但是他是一个较底层的微前端框架,所以配置复杂度很高,而且舞无箱隔离方案,所以实战中使用还是比较麻烦,不太推荐。