通过前面三篇文章,我们已经介绍了微前端的核心概念、路由与加载原理、隔离与通信机制。这篇文章,聚焦微前端落地的关键环节:框架选型。
本文将深度解析当前主流的微前端方案,从技术特点、核心优势、适用场景等维度做全面对比。
一、先明确:框架选型的核心维度
在对比具体框架之前,需要先建立统一的选型标准。一个合适的微前端框架,需要从以下几个维度评估:
- 易用性:是否开箱即用、文档是否完善、集成主/子应用的配置步骤复杂度。对团队而言,低上手成本意味着更快的落地速度。
- 兼容性:是否支持多种前端技术栈、是否兼容低版本浏览器、是否支持遗留系统。兼容性是微前端框架落地的前提。
- 性能:子应用加载速度、资源重复加载情况、沙箱隔离的性能损耗、运行时的内存占用。性能直接影响用户体验。
- 生态:生态是否成熟、社区活跃度、是否有大型企业背书。生态是衡量框架长期维护能力的重要指标。
- 团队匹配度:框架的技术依赖是否与团队现有技术栈兼容。
二、主流框架深度解析
接下来,逐一拆解 Single-Spa、Qiankun、Module Federation/EMP、Micro App、wujie 的主要特点及核心机制实现方式。
| 框架 | 易用性 | 兼容性 | 性能 | 生态 | 综合特点 |
|---|---|---|---|---|---|
| Single-SPA | ⭐️⭐️ | ⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️ | 灵活但需自研上层能力 |
| Qiankun | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️⭐️ | 开箱即用,强隔离,中后台首选 |
| EMP | ⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️ | Module Federation 的企业封装 |
| Micro App | ⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️ | ⭐️⭐️⭐️ | ⭐️⭐️ | Vue 友好,轻量但生态弱 |
| Wujie | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️ | ⭐️⭐️⭐️⭐️ | 零侵入、强隔离、保活支持,新锐方案 |
1. Single-SPA
Single-SPA 是 2016 年诞生的微前端框架,也是微前端概念的最早实践者。
♠️ 核心定位是"微前端路由调度器",只负责子应用的注册、路由匹配和生命周期管理,不提供沙箱隔离、样式隔离等附加功能。

核心机制实现
路由分发
通过一个顶层路由器来管理各个微应用的路由。这个路由器监听 URL 的变化,并根据路由规则决定加载哪个微应用。
► 基于原生浏览器事件 popstate 和 hashchange 来实现的,同时也会监听 pushState 和 replaceState 的调用。
► 每个微应用需要暴露三个生命周期函数:bootstrap、mount 和 unmount。当路由匹配时,Single-SPA 会加载对应的微应用,并依次调用其生命周期函数。
► 路由规则是通过在注册微应用时提供的 activityFunction 来定义的。这个函数会根据当前的 URL(location)返回一个布尔值,表示该微应用是否应该被激活。
javascript
singleSpa.registerApplication(
"appName", // 子应用名称
() => System.import("appName"), // 加载函数,返回一个应用或者一个Promise
(location) => location.pathname.startsWith("appName"), // 激活函数,返回一个布尔值,表示该应用是否应该被激活
customProps: {
// 自定义属性,会被传递给子应用的 bootstrap、mount 和 unmount 函数
}
);
activityFunction 是一个纯函数,window.location 会作为第一个参数被调用,当函数返回的值为真(truthy)值时,应用会被激活。通常情况下,Activity function 会根据 window.location/后面的 path 来决定该应用是否需要被激活。
加载机制
本身并不直接提供加载微应用的功能,而是依赖于SystemJS、Webpack 等模块加载器。但是,它规定了微应用必须被包装成一个对象,该对象包含生命周期函数。
► 当路由匹配时,Single-SPA 会调用注册应用时提供的加载函数(如() => System.import('app1'))来获取微应用的导出模块
► 获取到微应用导出的生命周期函数后,Single-SPA 会缓存这些函数,并在适当的时机(如路由变化时)调用它们
隔离机制
并没有内置的 JS 沙箱机制、也没有自动的 CSS 隔离机制。
通信机制
没有内置的通信机制,需要手动实现。
优缺点总结
✔️ 优势:灵活性极高,可定制化程度强,适合需要深度自定义微前端体系的场景;支持所有技术栈,兼容性好。
❗️ 缺点:上手成本高,配置繁琐,需手动解决隔离、通信等问题;无法"开箱即用"。
典型适用场景
需要高度自定义微前端架构、兼容多种小众技术栈的项目。
2. Qiankun
Qiankun 是阿里开源的微前端框架,基于 Single-SPA 封装。
核心定位是"企业级微前端解决方案",补全了 Single-SPA 缺失的沙箱隔离、样式隔离、静态资源加载等核心功能。
核心机制实现
路由分发
支持 hash 和 history 两种模式。支持精确匹配、前缀匹配等多种激活规则,可配置路由守卫。
- history 模式通过重写
pushState/replaceState方法+监听popstate事件实现路由拦截; - hash 模式通过监听
hashchange事件实现;
► 注册微应用的基础配置信息。
► 当浏览器 url 发生变化时,会自动检查每一个微应用注册的 activeRule 规则,符合规则的应用将会被自动激活。
javascript
registerMicroApps([
{
name: "app1", // 子应用名称
entry: "//localhost:3001", // 子应用入口
activeRule: "/app1", // 激活规则
props: {
// 自定义属性
},
},
]);
加载机制
采用"HTML 入口加载"模式,主应用通过 fetch 请求子应用入口 HTML,解析 HTML 中的 JS/CSS 资源并动态加载;内置资源预加载机制,可配置 preloadApps 参数在浏览器空闲时预加载子应用资源;支持依赖共享,避免同一依赖重复加载。
► 加载子应用资源:通过 fetch 请求子应用的入口文件(HTML 或 JS)。
► 解析入口文件:如果是 HTML 格式,则解析其中的 JS 和 CSS 资源,然后加载。
► 执行子应用代码:在沙箱环境中执行子应用的 JS 代码,获取其导出生命周期函数。
► 挂载子应用:将子应用挂载到指定的容器节点上。
预加载机制
qiankun 提供了预加载子应用资源的功能,可以在浏览器空闲时加载子应用的静态资源
javascript
import { prefetchApps } from "qiankun";
prefetchApps([{ name: "app1", entry: "//localhost:3001" }]);
隔离机制
JS 沙箱:
- 开发环境默认使用 Proxy 沙箱(为每个子应用创建 window 代理,属性读写隔离);
- 降级使用 快照沙箱(记录挂载前后 window 差异,卸载时还原)。
CSS 隔离:
- 基础模式:子应用挂载时插入其 CSS,卸载时自动移除;
- 严格模式(
strictStyleIsolation: true):启用 Shadow DOM 实现强隔离(兼容性有限)。
通信机制
- Props 传递:主应用向子应用传入数据或方法;
- Global State:通过
initGlobalState()创建全局状态,支持跨应用监听变更; - 也可结合自定义事件总线(如 mitt)实现更复杂通信。
优缺点总结
✔️ 优势:开箱即用,配置简单;功能全面,覆盖企业级落地的核心需求;
❗️ 缺点:依赖 Single-SPA(自定义扩展需遵循框架规范)。
典型适用场景
大型中后台项目,特别是遗留系统重构(兼容旧技术栈)。
3.EMP
Module Federation 是 Webpack5 原生的"模块共享"方案。
EMP2.0 基于 Webpack5 的"微前端+模块联邦"方案,新版 EMP3.0 从 webpack 切换到 rspack(基于 Rust 的高性能构建引擎),来构建 JS。
Module Federation 核心定位是"跨应用模块共享",通过将不同应用的模块打包成"远程模块",实现应用间的模块复用和动态加载。++它并非传统意义上的微前端框架,而是从构建层面解决微前端的模块共享问题。++
EMP 核心基于 Module Federation 实现,定位为"企业级微前端模块联邦方案",通过封装 构建配置、路由系统、状态管理等能力,解决了 Module Federation 原生功能单一的问题,实现了"模块共享+微前端应用集成"的一体化解决方案
核心机制实现(EMP)
路由系统
基于 Module Federation,路由由主应用统一管理,子应用作为远程组件嵌入,无独立路由控制权。
加载机制
封装 Module Federation 配置,通过 CLI 自动生成 federated 构建配置,运行时动态加载远程模块。
继承 Module Federation 的"远程模块加载"核心,同时扩展了"应用级加载"能力。主应用通过 EMP 配置的 remotes 参数加载子应用远程模块;内置依赖共享优化,自动识别并共享公共依赖;支持按路由预加载子应用模块,提升页面切换速度;提供构建层面的资源优化,如代码分割、tree-shaking
隔离机制
无运行时隔离,依赖 MF 本身的模块边界和工程规范变更监听;
通信机制
通过共享模块(如状态管理库)通信
优缺点总结
✔️ 优势:开箱即用,性能优异;
❗️ 缺点:依赖 MF(Webpack5/3.0 rspack),对旧项目兼容性较差;社区文档、解决方案较少,问题排查成本高。
典型适用场景
主打 "组件 / 模块复用",适合需要共享通用组件、工具库的场景。实际项目中,可根据需求组合使用:用 EMP 实现模块 / 组件复用,用 qiankun 实现完整应用的嵌入。
4. Micro App
京东开源的"组件化微前端"方案
借鉴了 WebComponent 的思想,通过 js 沙箱、样式隔离、元素隔离、路由隔离模拟实现了 ShadowDom 的隔离特性,并结合 CustomElement 将微前端封装成一个类 WebComponent 组件,从而实现微前端的组件化渲染。

核心技术实现
路由分发
通过拦截浏览器路由事件以及自定义的 location、history,实现了一套虚拟路由系统,子应用运行在这套虚拟路由系统中,和主应用的路由进行隔离,避免相互影响。
虚拟路由系统分为四种模式:search、native、native-scope、pure
► search 模式:通子应用的路由信息会作为 query 参数同步到浏览器地址上;
► native 模式:直接使用浏览器的路由系统,子应用的路由完全由主应用管理;
► native-scope 模式:在 native 模式基础上,通过 URL 路径前缀(如 /app1/)来匹配子应用;
► pure 模式:子应用独立于浏览器进行渲染,即不会修改浏览器地址,也不会受其影响,其表现和 iframe 类似。
加载机制
类似 Qiankun,采用 HTML Entry:加载子应用 HTML,提取并执行 JS、插入 CSS,渲染子应用到指定容器节点。内置智能预加载机制,在浏览器空闲时预加载当前页面可能需要的子应用资源;支持资源加载错误重试、超时控制等容错机制。
► fetch 子应用 index.html ,解析出 js/css 资源列表;
► 创建沙箱,把资源注入沙箱运行 ;
► 生命周期钩子 bootstrap/mount/unmount。
隔离机制
- JS 沙箱:使用 Proxy 拦截了用户全局操作的行为,防止对 window 的访问和修改,避免全局变量污染;
- CSS 隔离:以标签作为样式作用域,利用标签的 name 属性为每个样式添加前缀,将子应用的样式影响禁锢在当前标签区域。
| 源码 | 转换后 |
|---|---|
.test {color: red;} |
micro-app[name=xxx] .test {color: red} |
通信机制
主应用和子应用之间的通信是绑定的,主应用只能向指定的子应用发送数据,子应用只能向主应用发送数据,这种方式可以有效的避免数据污染,防止多个子应用之间相互影响。
- 基础通信:通过
<micro-app>标签的 data 属性传递主 → 子初始化数据; - 全局通信:通过
microApp.setData/microApp.getDataAPI 实现主-子/子-子全局数据共享; - 自定义事件:通过
microApp.on/microApp.emitAPI 实现事件驱动的双向通信,支持事件命名空间,避免事件冲突
优缺点总结
✔️ 优势:使用简单,与框架无关;组件化使用方式符合前端开发习惯,上手难度低;
❗️ 缺点:浏览器兼容性稍弱(不支持 IE 浏览器);相比 Qiankun 生态成熟度稍低,部分边缘场景解决方案较少。
典型适用场景
需要快速接入微前端且子应用改造受限、多技术栈混用,子应用独立开发部署。
5. wujie
把子应用的代码在对应创建的 iframe 中执行,不需要特殊处理的上下文方法或属性代理到顶层上下文处理,需要特殊处理上下文方法改在 iframe 中修改后再代理出去,这样隔离处理会不会好一些 -- 源自[RFC] 关于沙箱隔离的一点想法 #286
wujie(无界)是腾讯开源的微前端框架,核心定位为"零侵入、高性能的微前端解决方案",通过自研的沙箱引擎和预编译机制,实现了子应用零改造接入,同时兼顾了高性能和强隔离特性,在移动端和 PC 端均有良好的适配表现。
核心机制实现(呼应前序博文核心知识点)
路由分发
在iframe内部进行history.pushState,浏览器会自动的在joint session history中添加iframe的session-history,浏览器的前进、后退在不做任何处理的情况就可以直接作用于子应用。
劫持iframe的history.pushState和history.replaceState,就可以将子应用的url同步到主应用的query参数上,当刷新浏览器初始化iframe时,读回子应用的url并使用iframe的history.replaceState进行同步。
加载机制
将子应用的js注入主应用同域的iframe中运行,iframe是一个原生的window沙箱,内部有完整的history和location接口,子应用实例instance运行在iframe中,路由也彻底和主应用解耦,可以直接在业务组件里面启动应用。
隔离机制
- JS 沙箱:将子应用的
js注入主应用同域的iframe中运行,iframe是一个原生的window沙箱 - CSS 隔离:采用webcomponent来实现页面的样式隔离,无界会创建一个
wujie自定义元素,然后将子应用的完整结构渲染在内部。子应用的实例instance在iframe内运行,dom在主应用容器下的webcomponent内,通过代理iframe的document到webcomponent,可以实现两者的互联。
通信机制
- props 注入机制 :子应用通过
$wujie.props可以轻松拿到主应用注入的数据 - window.parent 通信机制 :子应用
iframe沙箱和主应用同源,子应用可以直接通过window.parent和主应用通信 - 去中心化的通信机制 :无界提供了
EventBus实例,注入到主应用和子应用,所有的应用可以去中心化的进行通信
优缺点总结
✔️ 优势:天然物理隔离;多应用同时激活在线;
❗️缺点:相比 Qiankun、Micro App,社区生态稍小;部分小众技术栈适配案例较少。
典型适用场景
遗留系统迁移改造(无法修改子应用代码)、需要快速落地且子应用改造受限的场景。
三、快速体验
通过简单的 Hello World 示例,直观感受框架的使用方式。
1. Single-SPA
主应用注册子应用(main.js)
javascript
import { registerApplication, start } from 'single-spa';
// 注册子应用:约定子应用暴露bootstrap、mount、unmount钩子
registerApplication(
'app-vue', // 子应用名称
() => import('./src/app-vue/app.js'), // 加载子应用入口
location => location.pathname.startsWith('/app-vue'), // 激活规则
{ userInfo: { name: '奋飛' } } // 传递给子应用的props
);
// 启动Single-Spa
start();
子应用实现(app-vue/app.js):
javascript
// 实现约定的生命周期钩子
export async function bootstrap() {
console.log("app-vue bootstrap");
}
export async function mount(props) {
console.log("app-vue mount", props.userInfo);
// 渲染子应用到DOM
const appElement = document.createElement("div");
appElement.id = "app-vue";
appElement.innerHTML = "<h3>Hello World</h3>";
document.body.appendChild(appElement);
}
export async function unmount() {
console.log("app-vue unmount");
// 卸载子应用DOM
document.getElementById("app-vue").remove();
}
2. Qiankun
主应用注册子应用(main.js)
javascript
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'app-vue', // 子应用名称
entry: '//localhost:8081', // 子应用入口地址
container: '#subapp-container', // 子应用挂载容器
activeRule: '/app-vue', // 激活规则
props: { userInfo: { name: '奋飛' } } // 传递props
}
]);
// 启动Qiankun
start();
子应用改造( main.js):
javascript
// 子应用入口文件(main.js)
import { createApp } from "vue";
import App from "./App.vue";
let app = null;
// 暴露Qiankun生命周期钩子
export async function bootstrap() {}
export async function mount(props) {
app = createApp(App);
app.mount(props.container ? props.container.querySelector("#app") : "#app");
}
export async function unmount() {
app.unmount();
app = null;
}
3. EMP
以 React 为示例
生产者(导出组件的应用)
javascript
// 在 React 16/17 应用中
import React from 'react';
import { createBridgeComponent } from '@empjs/bridge-react';
// 创建要共享的组件
const MyComponent = (props) => {
return <div>Hello World from React 16/17! {props.message}</div>;
};
// 导出桥接组件
export default createBridgeComponent(MyComponent, {
React,
ReactDOM: require('react-dom'),
// React 18+ 才有 createRoot
// createRoot: require('react-dom/client').createRoot
});
消费者(使用组件的应用)
javascript
// 在 React 18/19 应用中
import React from 'react';
import { createRemoteAppComponent } from '@empjs/bridge-react';
// 导入远程组件(可以是动态导入)
import RemoteComponent from 'remote-app/MyComponent';
// 创建可在当前 React 版本中使用的组件
const BridgedComponent = createRemoteAppComponent(
RemoteComponent,
{
React,
ReactDOM: require('react-dom'),
createRoot: require('react-dom/client').createRoot
},
{
onError: (error) => console.error('Failed to load component:', error)
}
);
// 在应用中使用
function App() {
return (
<div>
<h1>My App (React 18/19)</h1>
<BridgedComponent message="Hello World" />
</div>
);
}
4. Micro App
主应用初始化(main.js)
javascript
import microApp from '@micro-zoe/micro-app'
// 初始化微应用
microApp.start();
主应用嵌入子应用(任意组件模板):
html
<!-- 一行代码嵌入子应用,name为子应用唯一标识,url为子应用入口 -->
<micro-app name="app-vue" url="//localhost:8081/"></micro-app>
子应用无需改造,直接启动即可(若存在跨域需配置 CORS):
javascript
// 子应用vue.config.js跨域配置
module.exports = {
devServer: {
headers: {
"Access-Control-Allow-Origin": "*",
},
},
};
5. wujie
主应用全局注册(main.js)
javascript
import { createApp } from 'vue'
import App from './App.vue'
import WujieVue from 'wujie-vue3'
const app = createApp(App)
app.use(WujieVue)
app.mount('#app')
主应用嵌入子应用(App.vue):
html
<template>
<div>
<h3>wujie主应用</h3>
<!-- 零侵入嵌入子应用,url为子应用入口 -->
<WujieVue
width="100%"
height="500px"
name="app-vue"
url="//localhost:8081/"
/>
</div>
</template>
子应用无需任何改造,直接启动即可(跨域配置同其他框架):
javascript
// 子应用vue.config.js跨域配置
module.exports = {
devServer: {
headers: {
"Access-Control-Allow-Origin": "*",
},
},
};
至此,明确了框架选型后。下一篇文章我们将进入实战环节------基于当前最主流的 Qiankun 框架,搭建一个企业级的微前端项目,覆盖 React 主应用+Vue3 子应用的跨框架场景,完整实现主应用搭建、子应用改造、跨应用通信、本地开发环境配置等核心流程。