2、技术选型对比:iframe、Web Components、Module Federation、qiankun、single-spa 的优缺点分析
做微前端,第一步就是选技术。这一步选错了,后面全是坑。
我见过不少团队,一上来就拍脑袋选 qiankun,结果项目跑起来发现根本不需要沙箱隔离。也见过硬上 Module Federation 的,最后被构建配置搞到崩溃。
今天我把主流的五个方案掰开揉碎讲清楚。你听完心里就有数了。
2.1 iframe:最古老,也最被低估
iframe 其实是被骂得最惨的方案。很多人一听 iframe 就摇头,说性能差、通信难、SEO 不行。
但说实话,iframe 的隔离性是最好的。没有之一。
核心优势:
- 天然隔离:CSS、JS、DOM 完全独立,互不干扰
- 子应用崩溃不影响主应用
- 几乎零改造,老项目直接嵌入
我在项目中遇到过这样的情况:一个用了 jQuery 1.x 的老系统,要集成到 React 18 的新平台里。用 qiankun 跑起来各种报错,最后直接用 iframe 嵌入,十分钟搞定。
但 iframe 的缺点也很明显:
- 通信成本高:postMessage 用起来很别扭,不像函数调用那么自然
- 路由不同步:刷新页面后,iframe 里的状态就丢了
- 弹窗/遮罩层出不来:子应用的弹窗只能局限在 iframe 区域内
- 性能开销:每个 iframe 都是一个独立的浏览器上下文,内存占用高
我的建议:
如果你只是临时集成一个第三方系统,或者子应用完全独立、不需要和主应用深度交互,iframe 反而是最省心的方案。别被技术鄙视链带偏了。
2.2 Web Components:标准化的未来,但现实很骨感
Web Components 是 W3C 的标准规范。理论上,它可以让不同框架的组件共存。
但实际用起来,嗯……有点尴尬。
先看优点:
- 标准化:浏览器原生支持,不需要额外框架
- Shadow DOM 隔离:样式和 DOM 完全隔离
- 跨框架复用:React、Vue、Angular 都能用
再看缺点:
- 生态不成熟:UI 组件库对 Web Components 的支持很差
- 框架集成麻烦:React 对 Web Components 的支持一直有问题,事件绑定、属性传递都需要额外处理
- 性能问题:大量使用 Shadow DOM 会导致渲染性能下降
- 调试困难:Shadow DOM 里的样式和 DOM 结构很难调试
避坑指南:
我曾经在一个项目中尝试用 Web Components 做微前端,结果发现 Ant Design 的组件根本没法用。因为 Ant Design 的样式是全局的,进不了 Shadow DOM。最后不得不手动注入样式,维护成本极高。
所以我的结论是:Web Components 适合做简单的跨框架组件,但不适合做完整的微前端方案。
2.3 Module Federation:Webpack 5 的杀手锏
Module Federation 是 Webpack 5 推出的功能。它让多个独立构建的应用可以共享模块。
说白了,就是运行时加载远程代码。
它的核心优势:
- 真正的去中心化:每个应用都可以暴露自己的模块,也可以加载别人的模块
- 共享依赖:可以配置共享的第三方库,避免重复加载
- 性能优秀:基于 Webpack 的代码分割,按需加载
- 类型安全:配合 TypeScript,可以做到编译时检查
举个例子,主应用可以这样加载远程组件:
// webpack.config.js (主应用)
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
},
})
// 在代码中使用
const RemoteButton = React.lazy(() => import('app1/Button'));
子应用暴露组件也很简单:
// webpack.config.js (子应用)
new ModuleFederationPlugin({
name: 'app1',
exposes: {
'./Button': './src/Button',
},
})
但 Module Federation 也有坑:
- 强依赖 Webpack 5:如果你用 Vite 或别的构建工具,需要额外插件
- 配置复杂:shared、exposes、remotes 这些配置项很容易搞错
- 版本冲突:共享依赖的版本不一致时,会出现奇怪的问题
- 没有沙箱隔离:CSS 和 JS 的隔离需要自己处理
我的经验:
Module Federation 最适合的场景是同一个技术栈内的模块共享。比如多个 React 应用之间共享组件库、工具函数。如果你要做跨技术栈的微前端,它还需要配合其他方案使用。
2.4 single-spa:微前端的元老
single-spa 是微前端的鼻祖。它定义了一套生命周期规范,让不同框架的应用可以共存。
它的核心思想很简单:
- 主应用负责路由分发
- 子应用暴露生命周期函数(bootstrap、mount、unmount)
- single-spa 根据路由切换,调用对应的生命周期
优点:
- 框架无关:React、Vue、Angular、甚至 jQuery 都能接入
- 轻量:核心库只有几十 KB
- 成熟稳定:社区活跃,文档完善
缺点:
- 没有样式隔离:CSS 需要自己处理
- 没有 JS 沙箱:全局变量污染需要自己解决
- 通信机制缺失:需要自己实现事件总线或状态管理
- 子应用改造成本高:需要修改子应用的入口文件
一句话总结:
single-spa 是一个基础框架,它只解决了「如何加载和卸载子应用」的问题。样式隔离、JS 沙箱、通信这些,都需要你自己去实现。
2.5 qiankun:single-spa 的增强版
qiankun 是基于 single-spa 封装的。它解决了 single-spa 最让人头疼的几个问题。
qiankun 的核心增强:
- JS 沙箱:基于 Proxy 实现,子应用之间的全局变量互不干扰
- 样式隔离:支持 Shadow DOM 和实验性样式隔离方案
- 预加载:可以在空闲时预加载子应用的资源
- 开箱即用:接入成本比 single-spa 低很多
接入方式也很简单:
// 主应用
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react-app',
entry: '//localhost:3001',
container: '#container',
activeRule: '/react',
},
]);
start();
但 qiankun 也不是银弹:
- 沙箱性能开销:Proxy 沙箱在大量操作时会有性能损耗
- 样式隔离不完美:实验性方案有兼容性问题,Shadow DOM 方案有局限性
- 子应用改造依然存在:虽然比 single-spa 少,但还是需要改一些代码
- 对老项目不友好:jQuery 项目接入 qiankun 经常出问题
避坑指南:
我曾经在一个项目中,子应用用了大量的 document.write 和 window.open。qiankun 的沙箱对这些操作的支持很差,最后不得不改子应用的代码。所以如果你要接入老项目,一定要先评估改造工作量。
2.6 横向对比:一张表说清楚
| 特性 | iframe | Web Components | Module Federation | single-spa | qiankun |
|---|---|---|---|---|---|
| 样式隔离 | ✅ 完美 | ✅ 完美 | ❌ 无 | ❌ 无 | ⚠️ 有但有限 |
| JS 隔离 | ✅ 完美 | ✅ 完美 | ❌ 无 | ❌ 无 | ✅ 有 |
| 通信成本 | ❌ 高 | ⚠️ 中 | ✅ 低 | ⚠️ 中 | ✅ 低 |
| 路由同步 | ❌ 难 | ⚠️ 需手动 | ✅ 自然 | ✅ 自然 | ✅ 自然 |
| 性能 | ⚠️ 中 | ⚠️ 中 | ✅ 高 | ✅ 高 | ⚠️ 中 |
| 接入成本 | ✅ 极低 | ⚠️ 中 | ⚠️ 高 | ⚠️ 中 | ✅ 低 |
| 生态成熟度 | ✅ 成熟 | ❌ 不成熟 | ⚠️ 发展中 | ✅ 成熟 | ✅ 成熟 |
| 跨技术栈 | ✅ 支持 | ✅ 支持 | ⚠️ 有限 | ✅ 支持 | ✅ 支持 |
2.7 我的选型建议
说了这么多,到底怎么选?我给出几个场景化的建议:
- 临时集成第三方系统 → 选 iframe。别折腾,十分钟搞定。
- 同技术栈的模块共享 → 选 Module Federation。性能好,体验佳。
- 跨技术栈的新项目 → 选 qiankun。开箱即用,社区成熟。
- 对隔离性要求极高 → 选 iframe + qiankun 混合方案。核心模块用 iframe,普通模块用 qiankun。
- 团队有精力折腾 → 选 single-spa。自由度最高,但需要自己补全缺失的功能。
- Web Components → 暂时不建议用于微前端。等生态成熟了再说。
最后说一句:
没有完美的技术方案,只有最适合你的。选型的时候,多想想你的团队能力、项目现状、维护成本。别为了技术而技术。