什么是 qiankun?
qiankun 是一个基于 single-spa 的微前端实现库,由蚂蚁金服团队开发。它旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。
在我最近的项目中,我有幸使用了 qiankun 来整合多个独立的前端应用,今天就来分享一下我的使用心得和实际案例。
为什么选择微前端?
在介绍 qiankun 的具体使用前,先简单说说为什么我们需要微前端:
-
技术栈无关 - 各个子应用可以使用不同的技术栈(React、Vue、Angular 等)
-
独立开发 - 各个团队可以独立开发、测试、部署自己的应用
-
渐进式迁移 - 可以逐步迁移老系统,而不是一次性重写
-
应用自治 - 每个微应用都是独立的代码库,有自己的发布流程
基础案例:主应用配置
1. 安装 qiankun
npm install qiankun
# 或者
yarn add qiankun
2. 主应用入口文件配置
// main.js
import { registerMicroApps, start } from 'qiankun';
// 注册微应用
registerMicroApps([
{
name: 'react-app', // 微应用名称
entry: '//localhost:7100', // 微应用入口
container: '#subapp-container', // 微应用挂载节点
activeRule: '/react', // 微应用激活规则
},
{
name: 'vue-app',
entry: '//localhost:7101',
container: '#subapp-container',
activeRule: '/vue',
},
]);
// 启动 qiankun
start({
sandbox: {
strictStyleIsolation: true, // 开启样式隔离
},
});
3. HTML 模板设置
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>主应用</title>
</head>
<body>
<div id="root">
<h1>主应用</h1>
<ul>
<li><a href="/react">React 应用</a></li>
<li><a href="/vue">Vue 应用</a></li>
</ul>
<div id="subapp-container"></div>
</div>
</body>
</html>
微应用配置
React 微应用配置
// react-app/src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
// 动态设置 webpack publicPath,防止资源加载出错
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// react-app/src/index.js
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
function render(props) {
const { container } = props;
ReactDOM.render(
<App />,
container ? container.querySelector('#root') : document.querySelector('#root')
);
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
// 生命周期函数必须返回 Promise
export async function bootstrap() {
console.log('[react16] react app bootstraped');
}
export async function mount(props) {
console.log('[react16] props from main framework', props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(
container ? container.querySelector('#root') : document.querySelector('#root')
);
}
Vue 微应用配置
// vue-app/src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// vue-app/src/main.js
import './public-path';
import Vue from 'vue';
import App from './App.vue';
let instance = null;
function render(props = {}) {
const { container } = props;
instance = new Vue({
render: h => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
}
Webpack 配置修改
// vue.config.js 或 webpack.config.js
const packageName = require('./package.json').name;
module.exports = {
devServer: {
headers: {
'Access-Control-Allow-Origin': '*', // 允许跨域
},
},
configureWebpack: {
output: {
library: `${packageName}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${packageName}`,
},
},
};
实际使用中的心得体会
1. 样式隔离问题
qiankun 提供了两种样式隔离方案:
start({
sandbox: {
strictStyleIsolation: true, // 使用 Shadow DOM 实现严格隔离
experimentalStyleIsolation: true, // 实验性样式隔离
}
});
在实际使用中,我发现 strictStyleIsolation虽然隔离效果好,但可能会影响一些 UI 库的样式。而 experimentalStyleIsolation是通过给样式添加前缀实现的,兼容性更好。
2. 应用间通信
qiankun 提供了简单的通信机制:
// 主应用初始化
import { initGlobalState } from 'qiankun';
const actions = initGlobalState({
user: { name: '张三' },
});
// 监听状态变化
actions.onGlobalStateChange((state, prev) => {
console.log('主应用: 状态变化', state, prev);
});
// 微应用中获取和设置状态
export function mount(props) {
// 监听状态变化
props.onGlobalStateChange((state, prev) => {
console.log('微应用: 状态变化', state, prev);
});
// 设置全局状态
props.setGlobalState({ user: { name: '李四' } });
}
3. 路由处理技巧
// 主应用路由配置
registerMicroApps([
{
name: 'app1',
entry: '//localhost:7100',
container: '#subapp-container',
activeRule: '/app1',
props: {
routerBase: '/app1', // 传递路由基础路径
}
},
]);
// 微应用中使用
if (window.POWERED_BY_QIANKUN) {
// 从主应用传递的 props 中获取路由基础路径
const { routerBase } = props;
// 在微应用路由配置中使用
}
遇到的坑与解决方案
1. 静态资源路径问题
微应用中的静态资源路径需要特别注意,解决方案是使用相对路径或动态设置 publicPath。
2. 第三方脚本冲突
有些第三方库会修改全局对象,可能导致冲突。解决方案是在微应用卸载时清理全局状态。
3. 开发环境调试
开发时可以通过设置 window.__POWERED_BY_QIANKUN__ = true来模拟微前端环境进行调试。
总结
经过几个月的实践,我认为 qiankun 是一个相当成熟的微前端解决方案。它解决了微前端架构中的很多复杂问题,让开发者可以更专注于业务逻辑。
优点:
-
接入简单,学习成本低
-
功能完善,文档清晰
-
社区活跃,问题解决及时
需要注意的地方:
-
样式隔离需要根据实际情况选择合适方案
-
应用间通信要设计合理,避免过度耦合
-
部署和运维相对复杂
总的来说,如果你的项目需要整合多个前端应用,或者正在进行前端架构的现代化改造,qiankun 绝对值得一试。希望我的经验对你有帮助!