Skip to content

微前端方案比较

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和iframeloadMicroApp自动隔离Broadcast Channel性能好,隔离性强浏览器兼容性要求大型应用
Module FederationWebpack 5特性动态导入依赖配置模块调用代码共享,性能好配置复杂,依赖Webpack 5代码复用要求高

基于 VitePress 的本地知识库