微前端的核心价值:
- 技术栈无关
- 独立开发、独立部署
- 增量升级
- 独立运行时(每个微应用之间状态隔离,运行时状态不共享)
1.iframe
iframe是一个比较传统的微前端技术方案,上手难度低,使用简单。
优点
- 天然隔离性
- 沙箱环境:iframe 自带浏览器级别的 JS/CSS 隔离。
- 安全限制:遵循同源策略,跨域场景下可限制恶意操作。
- 独立运行能力
- 技术栈无关性
- 低侵入性
- 无需额外构建工具或框架,接入成本低。
- 多页面支持
- 适合嵌入完整的独立页面(如第三方地图、文档工具)。
缺点
- 性能问题
- 重复加载:每个 iframe 需加载完整的 HTML/JS/CSS,资源无法共享(如公共依赖)。
- 内存消耗:多个 iframe 会导致内存占用高,可能引发页面卡顿。
- 通信开销:跨 iframe 通信依赖
postMessage
,性能较差。
- 用户体验差
- 布局限制:UI 不同步,DOM 结构不共享(如弹窗问题)。
- 加载状态:子应用加载无占位,可能显示空白或闪烁。
- 路由同步:父应用与 iframe 内的路由状态难以同步(如浏览器前进/后退)。
- 开发体验问题
- 调试困难:Chrome 开发者工具需单独切换 iframe 上下文。
- 构建配置:子应用需单独配置 CSP(内容安全策略)、跨域策略等。
- 样式隔离过度:父应用无法直接覆盖子应用样式,定制化困难。
- SEO 不友好
- 搜索引擎可能无法抓取 iframe 内的动态内容。
- 现代 API 限制
- 部分浏览器 API(如摄像头、地理位置)在跨域 iframe 中需额外授权。
适用场景
- 简单嵌入第三方页面(如广告、地图、文档预览)。
- 短期快速接入,且对性能、体验要求不高的场景。
2.qiankun
qiankun 是一个基于 single-spa
的微前端实现库。阿里系开源的微前端框架,使用人数较多。
特性
- 📦 基于 single-spa 封装,提供了更加开箱即用的 API。
- 📱 技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
- 💪 HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
- 🛡 样式隔离,确保微应用之间样式互相不干扰。
- 🧳 JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
- ⚡️ 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
- 🔌 umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。
缺点
- 2.x 不支持Vite。如果要使用 vite,可以考虑使用
vite-plugin-qiankun
插件; - 3.0加入了支持 vite,不过功能还待完善。
3.Micro-App
Micro App 是京东出的一款基于 Web Component 原生组件进行渲染的微前端框架,不同于目前流行的开源框架,它从组件化的思维实现微前端,旨在降低上手难度、提升工作效率。
4.无界
无界(Wujie)是腾讯开源的微前端框架,主打 轻量、零成本接入 和 极致性能,它是一种基于 Web Components + iframe 的全新微前端方案,通过 iframe 的优化实现沙箱隔离,同时避免了传统 iframe 的缺点。
5.方案对比
框架核心特性对比
特性 | Qiankun | Micro-App | 无界(Wujie) |
---|---|---|---|
底层原理 | 基于 Single-SPA + JS 沙箱 | Web Components + Proxy 沙箱 | Web Components + 优化版 iframe |
隔离性 | JS/CSS 沙箱(Proxy/Snapshot) | ShadowDOM + JS 沙箱 | iframe 原生隔离 + CSS 沙箱 |
接入成本 | 高(需适配生命周期) | 低(无侵入式接入) | 极低(零改造接入) |
通信方式 | initGlobalState / props | window.microApp / event | props / eventBus |
路由同步 | 需配置 activeRule | 自动同步(可选) | 自动同步 |
性能 | 中(沙箱代理开销) | 高(轻量无代理) | 高(iframe 优化版) |
兼容性 | IE11 需 Polyfill(Proxy 限制) | 需 Polyfill(Web Components) | 支持 IE11+(无 Proxy 依赖) |
预加载/缓存 | 支持 | 支持 | 支持(资源复用) |
保活模式 | 支持 | 支持 | 支持 |
社区生态 | 成熟(阿里开源),较长时间没更新 | 中等(京东团队),更新较快 | 较新(腾讯开源),更新较快 |
6.Web Component
Web Components 允许创建可重用的自定义元素,由三项主要技术组成:
- Custom Elements(自定义元素):一组 JavaScript API,允许定义自定义元素及其行为
- Shadow DOM(影子 DOM):一组 JavaScript API,用于将封装的"影子"DOM树附加到元素
- HTML Templates(HTML模板):
<template>
和<slot>
元素可以编写不在呈现页面中显示的标记模板
1.Custom Elements(自定义元素)
自定义元素允许定义自己的 HTML 标签并在页面上使用它们。
1.1 创建自定义元素
class MyElement extends HTMLElement {
constructor() {
super();
// 元素创建时的初始化代码
this.textContent = 'Hello, Web Components!';
}
// 定义元素被添加到文档时调用的方法
connectedCallback() {
console.log('元素被添加到DOM中');
}
// 定义元素从文档中移除时调用的方法
disconnectedCallback() {
console.log('元素从DOM中移除');
}
// 定义元素属性变化时调用的方法
attributeChangedCallback(name, oldValue, newValue) {
console.log(`属性 ${name} 从 ${oldValue} 变为 ${newValue}`);
}
// 定义需要观察的属性列表
static get observedAttributes() {
return ['my-attr'];
}
}
// 注册自定义元素
customElements.define('my-element', MyElement);
1.2 使用自定义元素
<my-element my-attr="value"></my-element>
2.Shadow DOM(影子 DOM)
Shadow DOM 允许将隐藏的 DOM 树附加到常规 DOM 树中的元素上,实现封装。
2.1 创建带 Shadow DOM 的自定义元素
class ShadowElement extends HTMLElement {
constructor() {
super();
// 创建影子DOM
const shadow = this.attachShadow({mode: 'open'});
// 创建元素
const wrapper = document.createElement('div');
wrapper.setAttribute('class', 'wrapper');
const style = document.createElement('style');
style.textContent = `
.wrapper {
color: blue;
border: 1px solid black;
padding: 10px;
}
`;
shadow.appendChild(style);
shadow.appendChild(wrapper);
wrapper.textContent = '这是一个带Shadow DOM的元素';
}
}
customElements.define('shadow-element', ShadowElement);
2.2 使用 Shadow DOM 元素
<shadow-element></shadow-element>
3.HTML Templates(HTML模板)
HTML 模板允许定义可重用的 HTML 结构,这些结构在页面加载时不会被渲染,但可以在运行时实例化。
3.1 使用模板
<template id="my-template">
<style>
.card {
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
margin: 10px;
width: 200px;
}
.title {
font-weight: bold;
margin-bottom: 5px;
}
</style>
<div class="card">
<div class="title"><slot name="title">默认标题</slot></div>
<div class="content"><slot name="content">默认内容</slot></div>
</div>
</template>
3.2 在自定义元素中使用模板
class TemplateElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const template = document.getElementById('my-template');
const instance = template.content.cloneNode(true);
shadow.appendChild(instance);
}
}
customElements.define('template-element', TemplateElement);
3.3 使用带插槽的元素
<template-element>
<span slot="title">自定义标题</span>
<span slot="content">这是自定义内容</span>
</template-element>
工具和库
虽然 Web Components 是原生技术,但有些库可以简化开发:
- Lit - Google开发的轻量级库,简化Web Components开发
- Stencil - 用于构建可重用Web Components的编译器
- Svelte - 可以编译为Web Components的框架
7.Module Federation
Webpack 5 引入了 Module Federation(模块联邦),它允许在多个独立构建的应用或微前端之间共享代码和依赖。
核心概念
- 跨应用共享模块:不同应用可以共享库、组件或任何模块
- 运行时动态加载:无需在构建时将所有代码打包在一起
- 独立部署:每个应用可以独立开发、构建和部署
- 版本控制:可以指定共享模块的版本要求
使用场景
- 微前端架构:多个团队独立开发的前端应用可以共享组件和状态
- 大型应用拆分:将巨型应用拆分为多个可独立部署的小应用
- 第三方组件库:跨项目共享UI组件而不需要发布到npm
- 渐进式迁移:逐步将旧系统迁移到新技术栈
8.qiankun 原理
核心实现原理可以概括为以下几个关键点:
1. 应用加载机制
Qiankun 通过以下方式加载子应用:
- HTML Entry:不同于 JS Entry,Qiankun 通过解析子应用的 HTML 文件来获取静态资源和入口脚本
- 资源加载:使用
import-html-entry
库来加载子应用的 HTML,解析其中的 JS/CSS 资源 - 沙箱执行:在隔离环境中执行子应用的 JavaScript 代码
2. JS 沙箱隔离
Qiankun 实现了三种沙箱机制来隔离子应用的 JavaScript 执行环境,并会根据环境选择对应的沙箱机制:
- SnapshotSandbox(快照沙箱):
- 在应用挂载时保存全局状态快照
- 应用卸载时恢复快照
- 适用于单实例场景
缺点: 遍历 window 上所有属性,性能差;同一时间只能激活一个微应用。
优点: 可以支持不兼容 Proxy 的浏览器。
- LegacySandbox(传统沙箱/单实例沙箱):
- 基于 Proxy 实现
- 记录应用运行时对 window 的修改
- 应用卸载时恢复这些修改
缺点: 同一时间只能运行一个应用;兼容性没有快照沙箱好。
优点: 不需要遍历 window 上的所有属性,性能比快照沙箱要好。
- ProxySandbox(多实例沙箱):
- 每个子应用都有独立的沙箱环境
- 通过 Proxy 拦截对 window 的访问和修改。主要实现在
constructor
中,创建一个fakeWindow
对象,通过 Proxy 代理这个对象,全程没有改变 window - 支持多实例同时运行
缺点: 兼容性没有快照沙箱好。
优点: 没有污染全局 window;支持多实例;性能好;
沙箱的选择机制:
判断浏览器环境是否支持 Proxy,不支持则选择快照沙箱,支持则选择单、多例沙箱。再根据配置和场景选择单、多例沙箱。
3. CSS 样式隔离
Qiankun 提供了两种样式隔离方案:
-
Shadow DOM:
- 将子应用挂载到 Shadow DOM 中
- 实现天然的样式隔离
-
Scoped CSS:
- 动态添加/移除
<style>
标签 - 应用卸载时移除对应的样式
- 动态添加/移除
-
动态样式表:
- 卸载子应用时移除其样式表,重新挂载时恢复
- 有全局污染风险
选择机制:
默认使用动态样式表;若配置 strictStyleIsolation
为 true,则使用 Shadow DOM 方案;若配置 experimentalStyleIsolation
,则使用 Scoped CSS 方案。
4. 应用间通信
Qiankun 提供了以下通信方式:
-
全局状态管理:
- 通过
initGlobalState
初始化全局状态 - 子应用通过
onGlobalStateChange
监听状态变化 - 通过
setGlobalState
修改状态
- 通过
-
自定义事件:
- 基于浏览器原生 CustomEvent 实现
- 主应用和子应用可以通过事件进行通信
5. 子应用生命周期
Qiankun 管理子应用的生命周期,包括:
- bootstrap:应用初始化时调用
- mount:应用挂载时调用
- unmount:应用卸载时调用
- update:应用更新时调用(可选)
6. 路由劫持
Qiankun 通过重写 window.history
的相关方法(pushState/replaceState)来实现路由劫持,确保主应用能够正确捕获路由变化并加载对应的子应用。
实现流程示例
- 主应用注册子应用配置
- 用户访问特定路由时,主应用匹配到对应的子应用
- 加载子应用的 HTML 入口文件
- 解析 HTML 获取 JS/CSS 资源
- 创建沙箱环境
- 在沙箱中执行子应用的 JS 代码
- 将子应用挂载到指定的 DOM 容器
- 监听路由变化,在需要时卸载/加载子应用