Appearance
qiankun 实战案例
案例一:大型电商平台微前端改造
项目背景
某大型电商平台,包含用户中心、商品管理、订单系统、营销活动等多个业务模块,原单体应用代码庞大,开发效率低,部署复杂。
技术栈
- 主应用:Vue 3 + Vue Router + Pinia
- 微应用1:React 18 + Redux + Ant Design
- 微应用2:Vue 2 + Element UI
- 微应用3:Angular 15
实施步骤
1. 主应用改造
javascript
// main.js - 主应用入口
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { createMicroApp, startApp } from './micro-app';
import App from './App.vue';
// 创建主应用路由
const router = createRouter({
history: createWebHistory('/'),
routes: [
{ path: '/', component: () => import('./views/Home.vue') },
{ path: '/user', component: () => import('./views/UserContainer.vue') },
{ path: '/product', component: () => import('./views/ProductContainer.vue') },
{ path: '/order', component: () => import('./views/OrderContainer.vue') },
]
});
const app = createApp(App);
app.use(router);
// qiankun 配置
import { registerMicroApps, start } from 'qiankun';
const microApps = [
{
name: 'user-center',
entry: '//localhost:3001',
container: '#user-center-container',
activeRule: location => location.pathname.startsWith('/user'),
props: {
router,
store: app.config.globalProperties.$store
}
},
{
name: 'product-management',
entry: '//localhost:8080',
container: '#product-container',
activeRule: location => location.pathname.startsWith('/product')
},
{
name: 'order-system',
entry: '//localhost:4200',
container: '#order-container',
activeRule: location => location.pathname.startsWith('/order')
}
];
registerMicroApps(microApps, {
beforeLoad: app => {
console.log('[MainApp] before load', app.name);
return Promise.resolve();
},
beforeMount: app => {
console.log('[MainApp] before mount', app.name);
return Promise.resolve();
},
afterMount: app => {
console.log('[MainApp] after mount', app.name);
return Promise.resolve();
},
beforeUnmount: app => {
console.log('[MainApp] before unmount', app.name);
return Promise.resolve();
},
afterUnmount: app => {
console.log('[MainApp] after unmount', app.name);
return Promise.resolve();
}
});
// 启动 qiankun
start({
prefetch: true,
sandbox: {
strictStyleIsolation: true,
experimentalStyleIsolation: false
},
// 全局状态管理
...initGlobalState({
user: { id: 1, name: 'admin' },
theme: 'dark'
})
});
app.mount('#app');
2. React 微应用实现
javascript
// user-center/src/main.js - React 微应用
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import store from './store';
let reactApp = null;
// qiankun 生命周期
export async function bootstrap(props) {
console.log('React app bootstrap', props);
}
export async function mount(props) {
console.log('React app mount', props);
const { container, store: mainStore } = props;
// 整合主应用状态
const integratedStore = store;
if (mainStore) {
// 合并状态逻辑
integratedStore.dispatch({
type: 'SET_MAIN_STORE',
payload: mainStore
});
}
reactApp = (
<Provider store={integratedStore}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
);
ReactDOM.render(
reactApp,
container ? container.querySelector('#react-root') : document.getElementById('react-root')
);
}
export async function unmount(props) {
console.log('React app unmount', props);
if (reactApp) {
ReactDOM.unmountComponentAtNode(
props.container
? props.container.querySelector('#react-root')
: document.getElementById('react-root')
);
reactApp = null;
}
}
// 独立运行支持
if (!window.__POWERED_BY_QIANKUN__) {
ReactDOM.render(<App />, document.getElementById('root'));
}
3. Vue 2 微应用实现
javascript
// product-management/src/main.js - Vue 2 微应用
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
let vueApp = null;
export async function bootstrap(props) {
console.log('Vue2 app bootstrap', props);
}
export async function mount(props) {
console.log('Vue2 app mount', props);
const { container, history, onGlobalStateChange, setGlobalState } = props;
// 设置全局状态监听
if (onGlobalStateChange) {
onGlobalStateChange((state, prev) => {
console.log('Global state changed:', state, prev);
// 更新本地状态
if (state.user) {
store.commit('SET_USER', state.user);
}
}, true);
}
// 创建 Vue 实例
vueApp = new Vue({
router: createMicroRouter(history, router),
store,
render: h => h(App),
});
vueApp.$mount(container ? container.querySelector('#app') : '#app');
}
export async function unmount(props) {
console.log('Vue2 app unmount', props);
if (vueApp) {
vueApp.$destroy();
vueApp.$el.innerHTML = '';
vueApp = null;
}
}
// 为微应用创建适配的路由
function createMicroRouter(mainHistory, microRouter) {
if (window.__POWERED_BY_QIANKUN__) {
// 在微前端环境下使用主应用的 history
return microRouter;
}
return microRouter;
}
// 独立运行支持
if (!window.__POWERED_BY_QIANKUN__) {
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app');
}
遇到的挑战与解决方案
1. 样式隔离问题
css
/* 解决方案:使用 CSS Modules 或命名空间 */
/* 在微应用中使用特定前缀 */
.user-center-module {
.header {
background: #fff;
}
.content {
padding: 20px;
}
}
2. 状态同步问题
javascript
// 统一的状态管理解决方案
import { initGlobalState } from 'qiankun';
const { onGlobalStateChange, setGlobalState } = initGlobalState({
user: null,
permissions: [],
theme: 'light'
});
// 在各微应用中同步用户状态
onGlobalStateChange((state, prev) => {
if (state.user !== prev.user) {
// 更新本地用户状态
updateUserInMicroApp(state.user);
}
}, true);
案例二:企业级中后台系统
项目背景
某企业中后台系统,包含人事管理、财务管理、项目管理、报表系统等多个子系统,需要实现统一门户和独立开发部署。
架构设计
javascript
// 主应用架构
import { createApp } from 'vue';
import Layout from './components/Layout.vue';
import { registerMicroApps, start } from 'qiankun';
const app = createApp(Layout);
// 微应用配置
const enterpriseApps = [
{
name: 'hr-system',
entry: '//hr.company.com',
container: '#subapp-container',
activeRule: '/hr',
props: {
apiBase: '/api/hr',
permissions: ['hr:read', 'hr:write']
}
},
{
name: 'finance-system',
entry: '//finance.company.com',
container: '#subapp-container',
activeRule: '/finance',
props: {
apiBase: '/api/finance',
permissions: ['finance:read', 'finance:write']
}
},
{
name: 'project-system',
entry: '//project.company.com',
container: '#subapp-container',
activeRule: '/project',
props: {
apiBase: '/api/project',
permissions: ['project:read', 'project:write']
}
}
];
// 权限控制的微应用注册
registerMicroApps(
enterpriseApps.filter(app =>
hasPermission(app.props.permissions)
),
{
beforeLoad: (app) => {
// 检查应用权限
if (!hasAppPermission(app.name)) {
throw new Error(`No permission to access ${app.name}`);
}
return Promise.resolve();
}
}
);
start({
sandbox: {
strictStyleIsolation: true
},
prefetch: true
});
function hasPermission(requiredPermissions) {
const userPermissions = getUserPermissions();
return requiredPermissions.every(perm => userPermissions.includes(perm));
}
function hasAppPermission(appName) {
// 根据应用名称检查权限
return true; // 实际实现中会检查用户权限
}
用户认证集成
javascript
// 认证服务集成
class AuthService {
constructor() {
this.token = localStorage.getItem('auth-token');
this.refreshToken = localStorage.getItem('refresh-token');
}
async authenticate() {
if (!this.token) {
// 重定向到登录页
window.location.href = '/login';
return false;
}
// 验证 token 有效性
try {
const response = await fetch('/api/auth/validate', {
headers: {
'Authorization': `Bearer ${this.token}`
}
});
if (!response.ok) {
throw new Error('Token invalid');
}
return true;
} catch (error) {
// 刷新 token 或重新登录
return await this.refreshOrLogin();
}
}
async refreshOrLogin() {
if (this.refreshToken) {
try {
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ refreshToken: this.refreshToken })
});
if (response.ok) {
const data = await response.json();
this.token = data.token;
localStorage.setItem('auth-token', data.token);
return true;
}
} catch (error) {
console.error('Token refresh failed:', error);
}
}
// 重定向到登录
window.location.href = '/login?redirect=' + encodeURIComponent(window.location.href);
return false;
}
}
// 在主应用中集成认证
const authService = new AuthService();
// 检查认证状态
if (!await authService.authenticate()) {
// 认证失败,不启动微应用
console.error('Authentication failed, cannot start micro apps');
} else {
// 启动 qiankun
start({
sandbox: { strictStyleIsolation: true },
prefetch: true
});
}
案例三:多团队协作的微前端平台
项目背景
多个团队协作开发的大型平台,每个团队负责不同的业务域,需要实现技术栈无关的微前端架构。
工程化配置
javascript
// 主应用的 webpack 配置
const path = require('path');
const { ModuleFederationPlugin } = require('@module-federation/enhanced');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/main.js',
devServer: {
port: 8080,
headers: {
'Access-Control-Allow-Origin': '*',
},
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
new ModuleFederationPlugin({
name: 'main_app',
filename: 'remoteEntry.js',
remotes: {
// 可以与 Module Federation 集成
},
shared: {
vue: { singleton: true },
'vue-router': { singleton: true },
}
})
]
};
微应用标准化模板
javascript
// 微应用通用模板
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';
// 通用微应用生命周期
export async function bootstrap(props) {
console.log(`${props.name} bootstrap`, props);
}
export async function mount(props) {
console.log(`${props.name} mount`, props);
const { container, routerBase = '/', name } = props;
// 创建微应用路由
const router = createRouter({
history: createWebHistory(routerBase),
routes: [
// 微应用特有路由
]
});
const app = createApp(App);
app.use(router);
// 挂载到指定容器
app.mount(container.querySelector('#app') || container);
// 保存应用实例以便卸载
window[`__${name.toUpperCase()}_APP__`] = app;
}
export async function unmount(props) {
console.log(`${props.name} unmount`, props);
const appName = props.name.toUpperCase();
const app = window[`__${appName}_APP__`];
if (app) {
app.unmount();
delete window[`__${appName}_APP__`];
}
}
// 独立开发模式
if (!window.__POWERED_BY_QIANKUN__) {
const app = createApp(App);
app.use(createRouter({
history: createWebHistory(),
routes: [] // 开发环境路由
}));
app.mount('#app');
}
CI/CD 集成
yaml
# .github/workflows/micro-app-deploy.yml
name: Deploy Micro App
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Build micro app
run: npm run build
env:
VUE_APP_BASE_URL: ${{ secrets.MICRO_APP_BASE_URL }}
VUE_APP_API_URL: ${{ secrets.API_URL }}
- name: Run tests
run: npm run test:unit
- name: Deploy to staging
if: github.ref == 'refs/heads/develop'
run: |
# 部署到预发布环境
scp -r dist/* user@staging-server:/var/www/micro-app/
- name: Deploy to production
if: github.ref == 'refs/heads/main'
run: |
# 部署到生产环境
scp -r dist/* user@prod-server:/var/www/micro-app/
- name: Notify main app
run: |
# 通知主应用更新微应用入口
curl -X POST ${{ secrets.MAIN_APP_UPDATE_HOOK }} \
-H "Content-Type: application/json" \
-d '{"app": "${{ github.event.repository.name }}", "version": "${{ github.sha }}"}'
性能优化实践
1. 预加载策略
javascript
// 智能预加载
import { start } from 'qiankun';
// 基于用户行为的预加载
class IntelligentPrefetch {
constructor() {
this.userBehavior = {
visitedPages: [],
timeOnPage: {},
navigationPattern: []
};
}
recordBehavior(page, time) {
this.userBehavior.visitedPages.push(page);
this.userBehavior.timeOnPage[page] = time || Date.now();
if (this.userBehavior.visitedPages.length > 10) {
this.userBehavior.visitedPages.shift();
}
}
predictNextMicroApp() {
const recentPages = this.userBehavior.visitedPages.slice(-3);
// 电商场景预测逻辑
if (recentPages.includes('/product') && recentPages.includes('/cart')) {
return 'checkout'; // 可能会访问结算页面
}
// 中后台场景预测
if (recentPages.includes('/hr/employees') && recentPages.includes('/hr/departments')) {
return 'hr/reports';
}
return null;
}
}
const prefetchManager = new IntelligentPrefetch();
start({
prefetch: () => {
const predictedApp = prefetchManager.predictNextMicroApp();
if (predictedApp) {
return [predictedApp];
}
return ['common-apps']; // 默认预加载常用应用
}
});
2. 资源优化
javascript
// 微应用资源优化配置
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
// 分离公共依赖
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10
},
// 分离 UI 库
uiLibrary: {
test: /[\\/]node_modules[\\/](element-ui|ant-design-vue|@angular[\\/]/,
name: 'ui-library',
chunks: 'all',
priority: 8
}
}
}
}
};
故障排查与监控
1. 错误监控
javascript
// 微应用错误监控
class MicroAppMonitor {
constructor() {
this.errorQueue = [];
this.performanceMetrics = {};
}
init() {
// 监控微应用错误
window.addEventListener('error', (event) => {
this.reportError({
type: 'javascript',
message: event.error.message,
stack: event.error.stack,
microAppName: this.getCurrentMicroApp(),
url: window.location.href,
timestamp: Date.now()
});
});
window.addEventListener('unhandledrejection', (event) => {
this.reportError({
type: 'unhandled-promise',
message: event.reason.message || event.reason,
stack: event.reason.stack,
microAppName: this.getCurrentMicroApp(),
url: window.location.href,
timestamp: Date.now()
});
});
}
reportError(error) {
this.errorQueue.push(error);
// 批量上报
if (this.errorQueue.length >= 5) {
this.flushErrors();
}
console.error('Micro app error:', error);
}
flushErrors() {
if (this.errorQueue.length > 0) {
fetch('/api/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
errors: this.errorQueue,
userAgent: navigator.userAgent,
timestamp: new Date().toISOString()
})
}).catch(err => {
console.error('Failed to report errors:', err);
});
this.errorQueue = [];
}
}
getCurrentMicroApp() {
// 根据当前路由判断当前微应用
const path = window.location.pathname;
const microAppMap = {
'/user': 'user-center',
'/product': 'product-management',
'/order': 'order-system',
'/hr': 'hr-system',
'/finance': 'finance-system'
};
for (const [route, appName] of Object.entries(microAppMap)) {
if (path.startsWith(route)) {
return appName;
}
}
return 'unknown';
}
}
const monitor = new MicroAppMonitor();
monitor.init();
通过这些实战案例,我们可以看到 qiankun 在不同场景下的应用方式和解决方案,包括电商平台、企业中后台和多团队协作等复杂场景。