qiankun 微前端框架
一、基础介绍
1.1 什么是 qiankun
qiankun 框架 是阿里巴巴开源的一款基于 微前端架构 的解决方案,基于 Single-SPA 的二次封装,提供了更完善的开发体验和开箱即用的功能。
1.2 应用场景
- 大型企业级应用:需要多个团队协作开发,不同模块使用不同技术栈
- 逐步重构:将旧系统逐步迁移到新技术栈,同时保持原有功能可用
- 独立部署需求:子应用需要频繁更新,但主应用保持稳定
1.3 核心特性
- 技术栈无关:支持任意前端框架(React、Vue、Angular、jQuery 等)
- 独立开发部署:子应用可独立开发、独立部署、独立运行
- 样式隔离:确保子应用样式互不影响
- JS 沙箱:提供 JS 运行环境隔离
- 资源预加载:支持子应用资源预加载
- 应用通信:提供灵活的应用间通信方案
二、基本使用
2.1 主应用配置
import { registerMicroApps, start } from "qiankun";
registerMicroApps([
{
name: "vue-app",
entry: "//localhost:7100",
container: "#subapp-container",
activeRule: "/vue",
},
]);
start();
2.2 子应用适配
export async function mount(props) {
ReactDOM.render(<App />, props.container);
}
export async function unmount(props) {
ReactDOM.unmountComponentAtNode(props.container);
}
三、核心实现原理
3.1 路由劫持
class RouterHijacker {
constructor(apps) {
this.apps = apps;
this.currentApp = null;
// 监听路由变化
window.addEventListener("hashchange", this.routeChange.bind(this));
window.addEventListener("popstate", this.routeChange.bind(this));
}
routeChange() {
const { pathname } = window.location;
const app = this.apps.find((app) => {
return typeof app.activeRule === "string"
? pathname.startsWith(app.activeRule)
: app.activeRule(pathname);
});
if (app && app !== this.currentApp) {
if (this.currentApp) {
this.currentApp.unmount();
}
app.mount();
this.currentApp = app;
}
}
}
3.2 JS 沙箱实现
3.2.1 Proxy 代理沙箱(现代浏览器)
class ProxySandbox {
constructor() {
this.fakeWindow = {};
this.proxy = new Proxy(this.fakeWindow, {
get: (target, key) => target[key] || window[key],
set: (target, key, value) => {
target[key] = value;
return true;
},
});
}
}
3.2.2 快照沙箱(兼容模式)
class SnapshotSandbox {
constructor() {
this.windowSnapshot = {};
this.modifyPropsMap = {};
}
active() {
// 记录当前window快照
for (const prop in window) {
this.windowSnapshot[prop] = window[prop];
}
// 恢复之前的修改
Object.keys(this.modifyPropsMap).forEach((prop) => {
window[prop] = this.modifyPropsMap[prop];
});
}
inactive() {
// 记录被修改的属性
for (const prop in window) {
if (window[prop] !== this.windowSnapshot[prop]) {
this.modifyPropsMap[prop] = window[prop];
window[prop] = this.windowSnapshot[prop];
}
}
}
}
3.3 样式隔离
3.3.1 动态样式表(默认方案)
function loadStyles(css) {
const style = document.createElement("style");
style.textContent = css;
document.head.appendChild(style);
return () => style.remove();
}
3.3.2 Shadow DOM(可选方案)
- 将子应用的 DOM 和样式封装在 Shadow Root 中,实现天然隔离
3.4 应用通信
- 全局状态管理:通过
initGlobalState实现 - 事件总线:基于
CustomEvent实现
四、优化与注意事项
4.1 性能优化
- 预加载策略:使用
requestIdleCallback在空闲时预加载资源 - 资源缓存:通过
singular配置控制子应用缓存
4.2 常见问题
- 子应用需要适配生命周期钩子
- Web Components 和 Webpack 5 Module Federation 需要特殊处理
- 旧版浏览器兼容性问题
五、qiankun vs Single-SPA
single-spa 是微前端的“内核”,而 qiankun 是基于它的“完整操作系统”。如果你希望深入理解微前端的底层机制(如路由调度、生命周期管理),或需要高度定制化的架构,学习 single-spa 是必经之路;如果追求快速落地,直接使用 qiankun 更为高效。
| 特性 | single-spa | qiankun |
|---|---|---|
| 定位 | 底层框架,提供核心路由和生命周期 | 上层解决方案,封装 single-spa 并增强功能 |
| 隔离机制 | 需自行实现(如沙箱、样式隔离) | 内置 JS 沙箱、动态样式隔离 |
| 子应用加载方式 | JS Entry(需手动处理依赖) | HTML Entry(自动解析资源) |
| 开箱即用功能 | 无 | 预加载、通信机制、错误恢复等 |
| 上手难度 | 高(需处理大量细节) | 低(提供完整解决方案) |
| 适用场景 | 需要高度定制化的微前端架构 | 快速搭建企业级微前端应用 |
手写一个简易 single-spa
// 1. 注册子应用
const applications = [];
function registerApplication(appConfig) {
applications.push(appConfig);
}
// 2. 路由劫持
window.addEventListener("hashchange", reroute);
function reroute() {
const path = window.location.hash.slice(1);
applications.forEach((app) => {
const shouldMount = path.startsWith(app.activeWhen);
if (shouldMount && !app.mounted) {
app.app().then((childApp) => {
childApp.bootstrap();
childApp.mount({ domElement: document.getElementById(app.name) });
app.mounted = true;
});
} else if (!shouldMount && app.mounted) {
childApp.unmount();
app.mounted = false;
}
});
}
六、最佳实践
- 优先使用动态样式表方案,必要时再考虑 Shadow DOM
- 合理使用预加载,避免资源浪费
- 注意子应用生命周期管理
- 遵循官方文档建议的开发规范
更多详情请参考官方文档。