微前端框架对比分析

10 阅读9分钟

微前端

思想

  • 微前端是一种将单体前端应用拆分为多个小型、独立、可自治的前端模块的架构风格,灵感源于后端微服务思想,核心目标是让不同团队能用不同技术栈独立开发、测试、部署子应用,病无缝集成到同一用户界面中

核心原则

  • 技术无关:基座不限制子应用技术栈(React/Vue/Angule等)
  • 独立团队:按业务区域划分团队,遵循康威定律,自主研发运维
  • 代码隔离:JS/CSS运行在独立沙箱,避免全局污染
  • 共享基础设施:抽离权限、埋点、日志等公共能力为共享模块
  • 用户体验一直:整合后交互、样式、性能保持统一

主流实现方案对比

方案核心原理技术栈兼容性隔离性接入成本使用场景代表框架
Iframe原生浏览器隔离,嵌入子应用完全无关(任何技术栈)强(硬隔离)极低第三方嵌入、高安全隔离原生API
Single-SPA路由分发,动态加载子应用声明周期无关(支持多技术栈)弱(需自行处理)轻量整合、路由驱动场景single-spa
容器化整合沙箱+生命周期+资源加载无关(多技术栈友好)强(生产级)低(框架封装)企业级后台、遗留系统迁移qiankun(阿里)、micro-app(京东)、wujie(腾讯)
Webpack Module Federation(模块联邦)Webpack5原生能力,跨应用共享/加载模块弱(同Webpack技术栈,如React/Vue同生态)高(需深度定制Webpack配置)同技术栈大型应用、模块级复用(非完整子应用)Webpack5内置Module FederationPlugin
Web Compnents原生标准(Custom Elements + Shafow DOM + HTML Templates)无关(任意技术栈可封装为Web组件)中(Shadow DOM实现样式/DOM隔离,JS需自行隔离)中(需适配标准,兼容低版本浏览器需polyfill)通用组件复用(如通用按钮/表单)、低藕合业务组件原生API、Stencil、Lit

1. Iframe(浏览器原生嵌入)

核心定义

  • 基于浏览器原生标签,将子应用嵌入到基座应用的独立文档环境中,是最基础的微前端实现方式

实现原理

  • 每个Iframe对应的一个独立的Window上下文和DOM树,与主应用完全隔离
  • 主应用通过postMessage与子应用通信,子应用通过window.parent接收/发送消息
  • 子应用独立部署,主应用仅需通过src属性指向子应用地址

优缺点

  • 优点
    • 原生隔离,零兼容风险
    • 接入成本极低,虚无改造
    • 高安全隔离(适合第三方库)
    • 子应用完全独立,故障隔离
  • 缺点
    • 性能差,切换卡顿、内存占用高
    • 样式/布局难统一(Iframe边框,自适应问题)
    • 通信频繁(仅能通过postMessage)
    • 浏览器前进/后退按钮失效,路由无法共享

使用场景

  • 嵌入第三方不可信应用(如支付、底图、第三方报表)
  • 对体验要求低、隔离性要求极高的场景
  • 临时整合老系统,无需长期维护的场景

使用示例

// 基座应用
<!DOCTYPE html>
<html>
<body>
    <div>基座应用</div>
    <!-- 嵌入子应用 -->
    <iframe
        id='subApp'
        src='http://localhost:3000' <!-- 子应用地址 -->
        width='100%'
        height= '800px'
        frameborder='0'
    ></iframe>
    <script>
        // 主应用向子应用发消息
        const iframe = document.getElementById('subApp')
        iframe.contentWindow.postMessage({type: 'USER_INFO', data:{name: 'admin'}}, 'http://localhost:3000')
        // 主应用接收子应用消息
        window.addEventListener('message', e =>{
            if(e.origin === 'http://localhost:3000') {
                console.log('接收子应用消息:', e.data)
            }
        })
    </script>
</body>
</html>
<!-- 子应用 -->
<script>
    // 子应用接受主应用消息
    window.addEventListener('message', e => {
        if(e.orgin === 'http://localhost:8080') {
            console.log('接收主应用消息:', e.data)
            // 子应用向主应用回传消息
            window.parent.postMessage({type:'ACK', data: '已接收'}, 'http://localhost:8080')
        }
    })
</script>

2. Single-SPA

核心定义

  • 最早的微前端框架,核心是路由分发+子应用生命周期管理,将多个子应用挂载到基座应用的路由系统中,匹配路由时加载对应子应用

实现原理

  • 基座应用注册子应用(指定路由规则、容器、入口)
  • 监听路由变化,匹配到子应用路由时,动态加载子应用的JS/CSS资源
  • 调用子应用暴露的生命周期钩子(bootstrap/mount/unmount)完成挂载/卸载
  • 无原生隔离能力,需自行处理JS/CSS冲突

优缺点

  • 优点
    • 轻量、无侵入,多技术栈支持
    • 路由驱动,体验接近单应用
    • 可灵活扩展(如自行加沙箱)
  • 缺点
    • 无原生隔离,需手动处理JS/CSS冲突
    • 子应用需适应生命周期,接入成本高于iframe
    • 无开箱即用的通信方案,需自行实现

使用场景

  • 轻量级微前端整合,团队有能力自行处理隔离/通信
  • 多技术小型应用整合,无需复杂的沙箱/预加载
  • 作为基础框架,二次开发定制化微前端体系

使用示例

// 基座应用 --注册子应用
import { registermicroApps, start } form 'single-spa'
// 配置子应用
const microApps = [
    {
        name: 'vue-app', //子应用名称
        app: () => import('//localhost:8081/js/app.js'), // 子应用入口
        activeWhen: ['/vue'], // 匹配的路由
        customProps: { user: 'admin' } // 透传参数
    },
    {
        name: 'react-app',
        app: () => import('//localhost:3000/js/main.js'),
        activeWhen: ['/react']
    }
]
// 注册子应用
registerMicroApps(microApps,{
    beforeLoad: app => console.log('加载前:', app.name),
    mount: app => consoe.log('挂载后:', app.name)
})
// 启动Single-SPA
start({ urlRerouterOnly: true }) // 仅监听URL变化,不劫持点击事件
// 子应用(Vue) - 暴露生命周期
import Vue from 'vue'
import App from './App.vue'
let app = null
// 生命周期钩子
export async function bootstrap() {
    console.log('vue-app 初始化')
}

export async function mount(props) {
    app = new Vue({
        el:'#vue-container', // 基座提供的容器
        render: h => h(App, { props })
    })
}

export async function unmount() {
    app.$destroy();// 销毁Vue实例
    app = null;
}

3. 容器化整合(qiankun/micro-app/wujie)

核心定义

  • 基于Single-SPA扩展的企业级微前端框架,封装了沙箱隔离、样式隔离、通信、预加载等生产能力,是目前最主流的微前端

实现原理

  • 基座层: 路由匹配+子应用注册+声明周期管理(继承Single-SPA)
  • 隔离层:
    • JS隔离:Proxy代理window,实现快照式沙箱(子应用修改全局变量仅在沙箱内生效)
    • CSS隔离:动态添加/移除子应用样式表,或Shadow DOM隔离
  • 资源层:通过import-html-entry加载子应用HTML/CSS/JS,解析并动态注入
  • 通信层:提供props透传、全局状态、事件总线等开箱即用的通信方式

优缺点

  • 优点
    • 开箱即用,企业级能力全覆盖
    • 强隔离,无全局污染
    • 多通信方式,满足复杂场景
    • 预加载/缓存,性能优异
  • 缺点
    • 相比Single-SPA略重,有少量框架依赖
    • 极特殊场景(如修改document.title)需适配
    • 老浏览器(如IE)兼容需额外处理

使用场景

  • 企业级后台系统、大型ToB应用的微前端整合
  • 遗留系统(jQuery/AngularJS)渐进式迁移
  • 多团队协作的大型应用,需要严格隔离/统一体验
  • 对性能、稳定性要求高的生产环境

使用示例

// 基座应用
import { registerMicroApps, start, initGlobalState } from 'qiankun';
// 1. 初始化全局通信状态
const actions = initGlobalState({ user: 'admin'});
acions.onGlobalStateChange(state => {
    console.log('全局状态变化:', state)
})

// 2. 注册子应用
registerMictorApps([
    {
        name: 'react-app',
        entry:'//localhost:3000', // 子应用地址(支持跨域)
        container: '#subapp-container', // 挂载容器
        activeRule: '/react', // 激活路由
        props: { actions } // 透传通信方式
    }
], {
    beforeMount: [app => console.log('挂载前:', app.name)] // 全局生命周期钩子
})
// 3. 启动qiankun(开启严格样式隔离)
start({
    sanbox: { strictStyleIsolation: true},
    prefetch: true, // 开启预加载
    singular: true // 同一时间仅加载一个子应用
})
// 子应用(React) - 暴露生命周期
import ReactDOM from 'react-dom/client';
import App from './App'
let root = nulll;
export async function botstrap() {
    console.log('react-app 初始化')
}
export async function mount(props) {
    // 接收基座透传的参数/通信方式
    console.log('接收基座参数:', props)
    root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(<App {...props}/>)
}
export async function unmount() {
    root.unmount() // 卸载React应用
    root = null
}

4. Webpack Module Federation(模块联邦)

核心定义

  • Webpack5原生内置的模块共享能力,本质是跨应用模块加载,而非传统整页子应用整合,聚焦模块级复用的微前端方案
  • 不是传统微前端(完整子应用整合),而是模块级共享/远程加载--将应用拆分为远程模块和宿主模块,跨应用直接加载对方的组件/方法,无需打包到本地,是Webpack5为解决代码共享/重复打包设计的原生能力

实现原理

  • 远程应用:通过ModuleFederationPlugin暴露指定模块(组件/方法),生成remoteEntry.js作为入口
  • 宿主应用:通过插件配置远程应用地址,动态加载远程模块,如同加载本地模块 共享依赖:配置shared字段,实现React/Vue等公共库的复用,避免重复打包

优缺点

  • 优点
    • Webpack原生能力,无额外框架
    • 模块级复用,打包体积最优
    • 公共依赖复用,性能优异
    • 模块实时更新(无需重新打包)
  • 缺点
    • 技术栈绑定(Webpack5),异技术栈整合困难
    • 无原生隔离,需手动规范命名空间/样式
    • 接入成本高,需深入理解Webpack配置
    • 不适合整页子应用整合,仅聚焦模块复用

使用场景

  • 同技术栈(如React + Webpack5)的大型应用,需要模块级复用
  • 多应用共享核心组件/工具库,避免重复打包
  • 对大宝体积、加载性能要求极高的场景
  • 作为容器化整合的补充(如qiankun + Module Federation组合)

使用示例

// 远程应用(暴露模块) - webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container
module.exports = {
    plugins: [
        new ModuleFerationPlugin({
            name: 'remoteApp', // 远程应用唯一标识
            filename: 'remoteEntry.js', // 入口文件
            exposes: {
                './OrderList': './src/components/OrderList', // 暴露组件
                './utils:': './src/utils/index' // 暴露工具函数
            },
            // 共享依赖(单例模式,避免重复加载React)
            shared: {
                react: { singletion:true, requiredVersion: '^18.0.0 },
                'react-dom': { singleton: true }
            }
        })
    ]
}

// 宿主应用(加载模块)- webpack.config.js
new ModuleFederationPlugin({
  name: 'hostApp',
  remotes: {
    // 加载远程应用的模块
    remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js'
  },
  shared: { react: { singleton: true }, 'react-dom': { singleton: true } }
});

// 宿主应用使用远程模块
import React, { Suspense, lazy } from 'react';

// 动态加载远程组件(推荐,避免首屏阻塞)
const OrderList = lazy(() => import('remoteApp/OrderList'));
const { formatDate } = await import('remoteApp/utils'); // 加载远程工具函数

function App() {
  console.log('远程工具函数:', formatDate(new Date()));
  return (
    <Suspense fallback="Loading...">
      <OrderList />
    </Suspense>
  );
}