Appearance
微前端方案比较
iframe
工作原理
使用浏览器原生的iframe标签加载子应用,每个子应用运行在独立的沙箱环境中。
加载子组件
通过iframe的src属性指定子应用的URL,浏览器会自动加载整个子应用。
样式隔离
天然的样式隔离,子应用的样式不会影响父应用,反之亦然。
通信
- 父应用向子应用通信:
iframe.contentWindow.postMessage() - 子应用向父应用通信:
window.parent.postMessage() - 监听消息:
window.addEventListener('message', callback)
优缺点
- 优点:实现简单,完全隔离,兼容性好
- 缺点:性能开销大,页面加载慢,SEO不友好,用户体验差(滚动条、导航等)
使用场景
- 子应用与父应用完全独立,不需要共享状态
- 对性能要求不高的场景
- 快速集成第三方应用
具体使用案例
html
<iframe src="http://subapp.example.com" width="100%" height="600px"></iframe>Web Components
工作原理
使用浏览器原生的Web Components标准(Custom Elements、Shadow DOM、HTML Templates)创建可复用的组件。
加载子组件
通过自定义元素标签加载子组件,如 <my-component></my-component>。
样式隔离
使用Shadow DOM实现样式隔离,组件内部的样式不会影响外部。
通信
- 属性传递:
<my-component data="{...}"></my-component> - 事件监听:
element.addEventListener('custom-event', callback) - 方法调用:
element.someMethod()
优缺点
- 优点:标准原生,无需框架,样式隔离好
- 缺点:浏览器兼容性问题,开发复杂度高,与现有框架集成复杂
使用场景
- 跨框架的可复用组件
- 对性能要求高的场景
- 需要高度定制化的组件
具体使用案例
javascript
class MyComponent extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' })
this.shadowRoot.innerHTML = `
<style>/* 样式隔离 */</style>
<div>子应用内容</div>
`
}
}
customElements.define('my-component', MyComponent)single-spa
工作原理
基于路由的微前端框架,通过注册不同路由下的子应用,实现子应用的切换。
加载子组件
- 子应用需要导出bootstrap、mount、unmount三个生命周期函数
- 主应用通过single-spa注册子应用的路由和生命周期函数
样式隔离
默认没有样式隔离,需要手动处理(如CSS Modules、BEM命名等)。
通信
- 全局事件总线
- 共享状态库(如Redux、MobX)
- 自定义事件
优缺点
- 优点:轻量级,灵活性高,支持多种框架
- 缺点:需要手动处理样式隔离和通信,配置复杂
使用场景
- 多框架并存的项目
- 对灵活性要求高的场景
- 需要精细控制子应用生命周期的场景
具体使用案例
javascript
// 主应用
import { registerApplication, start } from 'single-spa'
registerApplication({
name: 'subapp1',
app: () => import('@org/subapp1'),
activeWhen: location => location.pathname.startsWith('/subapp1')
})
start()
// 子应用
export function bootstrap(props) {
/* 初始化 */
}
export function mount(props) {
/* 挂载 */
}
export function unmount(props) {
/* 卸载 */
}qiankun
工作原理
基于single-spa的微前端框架,提供了更完整的功能和更简单的配置。
加载子组件
- 子应用需要导出bootstrap、mount、unmount三个生命周期函数
- 主应用通过registerMicroApps注册子应用
样式隔离
- 自动的样式隔离(基于Shadow DOM或CSS Modules)
- 支持手动配置样式隔离策略
通信
- 基于Props的通信方式
- 全局状态管理(initGlobalState)
- 事件总线
优缺点
- 优点:功能完整,配置简单,支持自动样式隔离和通信
- 缺点:对打包工具和构建配置有一定要求
使用场景
- 企业级应用
- 多团队协作的大型项目
- 对开发体验要求高的场景
具体使用案例
javascript
// 主应用
import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
{
name: 'subapp1',
entry: 'http://localhost:8080',
container: '#subapp-container',
activeRule: '/subapp1'
}
])
start()
// 子应用
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
export async function bootstrap() {
/* 初始化 */
}
export async function mount(props) {
/* 挂载 */
}
export async function unmount() {
/* 卸载 */
}microapp
工作原理
基于Web Components的微前端框架,通过自定义元素加载子应用。
加载子组件
- 主应用使用
<micro-app>标签加载子应用 - 子应用无需修改,直接使用
样式隔离
- 自动的样式隔离(基于Shadow DOM)
- 支持样式穿透
通信
- 基于Props的通信
- 事件通信
- 数据共享
优缺点
- 优点:使用简单,无需修改子应用,自动样式隔离
- 缺点:对一些特殊场景的支持有限
使用场景
- 快速集成现有应用
- 对开发成本敏感的项目
- 中小规模的微前端应用
具体使用案例
html
<!-- 主应用 -->
<micro-app
name="subapp1"
url="http://localhost:8080"
baseroute="/subapp1"
></micro-app>
<script>
// 通信示例
const microAppElement = document.querySelector('micro-app')
microAppElement.addEventListener('datachange', e => {
console.log('子应用数据变化:', e.detail.data)
})
microAppElement.dispatchEvent(
new CustomEvent('data', { detail: { msg: 'Hello' } })
)
</script>wujie
工作原理
基于Web Workers和iframe的微前端框架,提供了更好的性能和隔离性。
加载子组件
- 主应用使用
loadMicroApp加载子应用 - 子应用无需修改,直接使用
样式隔离
- 自动的样式隔离
- 支持样式共享和穿透
通信
- 基于Broadcast Channel的通信
- 支持多种通信方式
优缺点
- 优点:性能好,隔离性强,使用简单
- 缺点:对浏览器兼容性有一定要求
使用场景
- 对性能要求高的场景
- 大型企业应用
- 需要严格隔离的场景
具体使用案例
javascript
// 主应用
import { loadMicroApp } from 'wujie'
loadMicroApp({
name: 'subapp1',
url: 'http://localhost:8080',
container: '#subapp-container',
props: {
/* 传递给子应用的参数 */
}
})Module Federation
工作原理
Webpack 5的新特性,允许不同应用之间共享模块,实现真正的代码共享。
加载子组件
- 通过
ModuleFederationPlugin配置共享模块 - 动态导入其他应用的模块
样式隔离
- 依赖于打包工具的配置
- 可以使用CSS Modules或其他样式隔离方案
通信
- 直接的模块调用
- 共享状态管理
- 事件总线
优缺点
- 优点:代码共享,性能好,灵活性高
- 缺点:依赖Webpack 5,配置复杂,对构建工具要求高
使用场景
- 同构应用
- 对代码复用要求高的场景
- 现代前端项目
具体使用案例
javascript
// 子应用webpack配置
new ModuleFederationPlugin({
name: 'subapp1',
filename: 'remoteEntry.js',
exposes: {
'./Component': './src/Component'
},
shared: ['react', 'react-dom']
})
// 主应用webpack配置
new ModuleFederationPlugin({
name: 'host',
remotes: {
subapp1: 'subapp1@http://localhost:8080/remoteEntry.js'
},
shared: ['react', 'react-dom']
})
// 主应用中使用
import('./subapp1/Component').then(({ default: Component }) => {
// 使用子应用组件
})总结比较
| 方案 | 工作原理 | 加载方式 | 样式隔离 | 通信方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|---|---|
| iframe | 浏览器原生 | src属性 | 天然隔离 | postMessage | 实现简单,完全隔离 | 性能差,用户体验差 | 第三方应用集成 |
| Web Components | 浏览器标准 | 自定义元素 | Shadow DOM | 属性、事件、方法 | 标准原生,样式隔离好 | 兼容性问题,开发复杂 | 跨框架组件 |
| single-spa | 路由切换 | 生命周期函数 | 手动处理 | 全局事件、共享状态 | 轻量级,灵活 | 配置复杂,需手动处理隔离 | 多框架并存 |
| qiankun | 基于single-spa | 生命周期函数 | 自动隔离 | Props、全局状态 | 功能完整,配置简单 | 对构建工具有要求 | 企业级应用 |
| microapp | 基于Web Components | 自定义元素 | 自动隔离 | Props、事件 | 使用简单,无需修改子应用 | 特殊场景支持有限 | 快速集成 |
| wujie | 基于Web Workers和iframe | loadMicroApp | 自动隔离 | Broadcast Channel | 性能好,隔离性强 | 浏览器兼容性要求 | 大型应用 |
| Module Federation | Webpack 5特性 | 动态导入 | 依赖配置 | 模块调用 | 代码共享,性能好 | 配置复杂,依赖Webpack 5 | 代码复用要求高 |