简介
qiankun 是阿里巴巴开源的一款基于Single-SPA的微前端框架,提供了更完善的沙箱隔离、资源加载和生命周期的管理能力,适用于大型企业级前端应用。
核心
- 开箱即用的沙箱隔离
- JS沙箱:通过Proxy 或with实现作用域隔离,避免全局变量污染;
- CSS沙箱:支持动态样式隔离,防止样式冲突(Shadow或Scoped Css)
- 简单易用的API
- registerMicroApps():注册子应用;
- start():启动qiankun;
- loadMicroApp():手动加载微应用(适用于非路由集成);
- 资源预加载
- 支持子应用资源预加载,提升用户体验;
- 样式隔离
- 支持Shadow或Scoped Css , 防止污染;
- 通信机制
- initGlobalstate():提供主子应用通信能力(基于props或customEvent)
- 子应用独立运行
- 子应用可以单独开发、部署、不影响主应用。
使用 Vue3 + TypeScript + QianKun + Vite 配置
主应用配置
1. 创建主应用
js
npm create vite@latest main-app --template vue-ts
cd main-app
npm install qiankun
2. 修改主应用配置(vite.config.ts)
ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins:[vue()],
server: {
port:9000, // 主应用端口
cors: true,
origin: 'http://localhost:9000'
},
})
3. 主应用入口文件(main.ts)
ts
import { createApp } from 'vue'
import App from './App.vue'
import { registerMicroApps, start } from 'qiankun'
const app createApp(App)
// 注册微应用
registerMicroApps([
{
name: 'vue3-sub-app', // 子应用名称
entry: '//localhost:9002', // 子应用地址
container: '#subapp-container', // 挂载容器
activeRule: '/vue3-sub-app', // 激活路由
props: { // 传递给子应用的数据
mainAppData: '来自主应用的数据'
}
}
])
// 启动qiankun
start({
sandbox: {
experimentalStyleIsolation:true // 开启样式隔离
}
})
4. 主应用App.vue
Vue
<template>
<div>
<h1>主应用 (Vue3 + Vite)</h1>
<router-link to="/vue3-sub-app">加载子应用</router-link>
<div id="subapp-container"></div>
</div>
</template>
子应用配置
1. 创建子应用
js
npm create vite@latest sub-app --template vue-ts
cd sub-app
npm install vite-plugin-qiankun --save-dev
2. 修改子应用配置 (vite.config.ts)
ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
plugins: [
vue(),
qiankun('vue3-sub-app', { // 子应用名称,与主应用注册时一致;
useDevMode: true
})
],
server: {
port: 9002,
cors: true,
origin: 'http://localhost:9002'
},
base: '/vue3-sub-app'
})
3. 子应用入口文件 (main.ts)
ts
import { createApp } from 'vue'
import App from './App.vue'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
import type { QiankunProps } from 'vite-plugin-qiankun/es/helper';
let app:ReturnType<typeof createApp> | null = null
// 独立运行逻辑
if (!qiankunWindow._POWERED_BY_QIANKUN_) {
createApp(App).mount('#app')
} else {
rederWithQiankun({
async bootstrap() {
console.log('子应用初始化');
},
// 挂载时
async mount(props:QiankunProps) {
console.log('子应用mount', props)
const container = props.container
? (props.container.querySelector('#app')
|| document.createElement('div'))
: document.getElementById('app');
if (!container) throw new Error('容器不存在');
// 清空容器(避免重复挂载)
container.innerHTML = '';
app = createApp(App)
app.mount(container)
},
// 卸载子应用
unmount(){
console.log('子应用unmount')
app?.unmount()
app = null
},
update(props) {
console.log('更新子应用参数', props)
}
})
}
通信机制
- 主应用向子应用传递数据
ts
// 主应用注册微应用时
registerMicroApps([
{
name: 'vue3-sub-app',
entry: '//localhost:5174',
container: '#subapp-container',
activeRule: '/vue3-sub-app',
props: { // 传递数据
mainAppData: '来自主应用的数据',
onGlobalStateChange: (state: any) => console.log('状态变化', state),
setGlobalState: (state: any) => console.log('设置状态', state)
}
}
])
- 子应用接收主应用数据
ts
// 子应用mount生命周期中
mount(props) {
console.log('接收主应用数据:', props.mainAppData)
// 监听主应用状态变化
props.onGlobalStateChange?.((state: any) => {
console.log('子应用监听到状态变化:', state)
}, true)
// 设置主应用状态
props.setGlobalState?.({ user: '子应用修改的用户' })
}
路由配置
- 主应用路由(router.ts)
ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: () => import('@/views/Home.vue')
},
{
path: '/vue3-sub-app', // 匹配子应用路由
component: () => import('@/views/SubAppContainer.vue'),
children: [
{
path: '', // 空路径匹配
name: 'subContainer',
component: () => import('@/views/subContainer/index.vue'),
},
{
path: ':pathMatch(.*)', // 通配符放在最后
name: 'subContainer',
component: () => import('@/views/subContainer/index.vue'),
},
]
}
]
})
export default router
- 子应用路由(router.ts)
ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/vue3-sub-app' : '/'),
routes: [
{
path: '/',
component: () => import('@/views/SubHome.vue')
},
{
path: '/about',
component: () => import('@/views/SubAbout.vue')
}
]
})
export default router