一、qiankun 核心特性与架构
- 技术栈无关:主应用和微应用可使用不同框架(Vue/React/Angular 等)
- 样式隔离:自动隔离各应用 CSS,避免样式污染
- JS 沙箱:运行时隔离,防止全局变量冲突
- 预加载:可配置微应用预加载策略,提升用户体验
- 简单易用:API 简洁,接入成本低
本次实践架构:
- 主应用(端口 8080):负责微应用的注册、加载和管理
- 微应用 1(端口 8081):Vue 3 实现的用户管理模块
- 微应用 2(端口 8082):Vue 3 实现的订单管理模块
二、环境准备
确保环境满足:
-
Node.js ≥ 14.x
-
Vue ≥ 3.x(主应用和微应用)
-
qiankun ≥ 2.0.0
bash
# 安装 qiankun(仅主应用需要)
npm i qiankun -S
三、实战步骤
1. 创建项目结构
# 创建主应用
vue create main-app
cd main-app
vue add router
npm i qiankun -S # 主应用安装 qiankun
cd ..
# 创建微应用1(用户模块)
vue create user-app
cd user-app
vue add router
cd ..
# 创建微应用2(订单模块)
vue create order-app
cd order-app
vue add router
cd ..
2. 配置微应用(以 user-app 为例)
微应用需要暴露生命周期钩子,供主应用调用。
(1)修改入口文件(main.js)
// user-app/src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
let app = null;
// 渲染函数
function render(props = {}) {
const { container } = props;
app = createApp(App);
app.use(router)
.mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时直接渲染
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
// 暴露 qiankun 生命周期钩子
export async function bootstrap() {
console.log('user-app bootstrap');
}
export async function mount(props) {
console.log('user-app mount', props);
render(props); // 传入主应用传递的参数
}
export async function unmount() {
console.log('user-app unmount');
app.unmount(); // 卸载应用
app = null;
}
(2)配置路由(router/index.js)
微应用路由需要添加基础路径,避免与主应用路由冲突:
// user-app/src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import UserList from '../views/UserList.vue'
const routes = [
{
path: '/',
name: 'UserList',
component: UserList
}
]
const router = createRouter({
// 基础路径:独立运行时为 '/', 被嵌入时由主应用传入
history: createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/user' : '/'),
routes
})
export default router
(3)配置 vue.config.js
需要允许跨域并指定入口文件:
// user-app/vue.config.js
module.exports = {
devServer: {
port: 8081,
headers: {
'Access-Control-Allow-Origin': '*' // 允许跨域
}
},
configureWebpack: {
output: {
// 打包格式必须为 umd
library: `user-app-[name]`,
libraryTarget: 'umd',
chunkLoadingGlobal: `webpackJsonp_user-app`
}
}
}
(4)创建页面组件
<!-- user-app/src/views/UserList.vue -->
<template>
<div class="user-list">
<h2>用户管理</h2>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.role }}
</li>
</ul>
</div>
</template>
<script setup>
const users = [
{ id: 1, name: '张三', role: '管理员' },
{ id: 2, name: '李四', role: '普通用户' }
]
</script>
3. 配置主应用(main-app)
主应用负责注册和管理微应用。
(1)注册微应用(main.js)
// main-app/src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { registerMicroApps, start } from 'qiankun'
const app = createApp(App)
app.use(router).mount('#app')
// 注册微应用
registerMicroApps([
{
name: 'user-app', // 微应用名称
entry: '//localhost:8081', // 微应用入口
container: '#micro-app-container', // 挂载容器
activeRule: '/user', // 激活路由规则
props: { // 传递给微应用的参数
token: 'main-app-token'
}
},
{
name: 'order-app',
entry: '//localhost:8082',
container: '#micro-app-container',
activeRule: '/order'
}
])
// 启动 qiankun
start({
sandbox: { strictStyleIsolation: true } // 开启严格样式隔离
})
(2)配置路由(router/index.js)
// main-app/src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/user', // 对应 user-app 的激活规则
name: 'User',
component: () => import('../views/MicroApp.vue')
},
{
path: '/order', // 对应 order-app 的激活规则
name: 'Order',
component: () => import('../views/MicroApp.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
(3)创建微应用容器组件
<!-- main-app/src/views/MicroApp.vue -->
<template>
<!-- 微应用挂载点 -->
<div id="micro-app-container"></div>
</template>
(4)修改 App.vue 添加导航
<!-- main-app/src/App.vue -->
<template>
<div id="app">
<nav>
<router-link to="/">首页</router-link> |
<router-link to="/user">用户管理</router-link> |
<router-link to="/order">订单管理</router-link>
</nav>
<router-view/>
</div>
</template>
4. 主应用与微应用通信
qiankun 提供了全局状态管理机制,实现应用间通信。
(1)主应用发送数据
// main-app/src/main.js
import { initGlobalState } from 'qiankun'
// 初始化全局状态
const initialState = {
userInfo: null
}
const actions = initGlobalState(initialState)
// 监听状态变化
actions.onGlobalStateChange((state, prev) => {
console.log('主应用监听状态变化:', state, prev)
})
// 主应用更新状态
setTimeout(() => {
actions.setGlobalState({
userInfo: { name: 'main-app-user' }
})
}, 3000)
(2)微应用接收数据
// user-app/src/main.js
export async function mount(props) {
// 接收主应用传递的通信方法
props.onGlobalStateChange((state, prev) => {
console.log('user-app 监听状态变化:', state, prev)
}, true)
// 微应用更新状态
props.setGlobalState({
userInfo: { name: 'user-app-user' }
})
render(props);
}
5. 运行效果验证
-
分别启动三个应用:
# 主应用 cd main-app && npm run serve # 用户微应用 cd user-app && npm run serve # 订单微应用 cd order-app && npm run serve -
访问
http://localhost:8080,可通过导航切换不同微应用,观察应用加载和切换效果。
四、生产环境部署注意事项
-
跨域配置:生产环境需在微应用服务器配置 CORS
-
静态资源路径:微应用打包时需配置正确的
publicPath -
部署路径:如果微应用部署在非根路径,需同步修改
activeRule和路由基础路径 -
性能优化:配置预加载策略,减少切换时的加载时间:
// 主应用 main.js start({ prefetch: 'all' // 预加载所有微应用 })
git地址:gitee.com/xcxsj/vue-q…