微前端改造总结
项目概述
本项目是一个基于 Qiankun 的微前端架构示例,包含以下三个应用:
- main-pro: 主应用(端口号:9000)
- son-pro: 子应用1(端口号:9001)
- son-pro1: 子应用2(端口号:9002)
技术栈
- 框架: Vue 3 + TypeScript
- 构建工具: Vite 4.3.9
- 路由: Vue Router 4.6.4
- 状态管理: Pinia 3.0.4
- UI组件库: Element Plus 2.13.0
- 微前端框架: Qiankun 2.10.16(主应用)、vite-plugin-qiankun 1.0.15(子应用)
- HTTP客户端: Axios 1.13.2
- 工具库: @vueuse/core 14.1.0
微前端改造步骤
一、主应用改造(main-pro)
1. 安装依赖
pnpm install qiankun
2. 配置入口文件(main.ts)
- 导入 qiankun 的
registerMicroApps、start、initGlobalState - 初始化全局状态管理
- 创建 Vue 应用实例并挂载
- 注册微应用
- 启动 qiankun
3. 配置路由(router/index.ts)
- 使用 Hash 模式路由
- 配置主应用的路由规则
- 添加路由守卫
4. 配置主应用容器(App.vue)
- 创建微应用挂载容器
<div id="subapp-container"></div> - 添加导航链接指向子应用路由
5. 注册微应用
在 main.ts 中配置:
registerMicroApps(
[
{
name: 'son-pro',
entry: '//localhost:9001',
container: '#subapp-container',
activeRule: '/#/son-pro',
},
{
name: 'son-pro1',
entry: '//localhost:9002',
container: '#subapp-container',
activeRule: '/#/son-pro1',
},
],
{
beforeLoad: async app => console.log('before load', app.name),
beforeMount: [async app => console.log('before mount', app.name)],
afterMount: [async app => console.log('after mount', app.name)],
beforeUnmount: [async app => console.log('before unmount', app.name)],
afterUnmount: [async app => console.log('after unmount', app.name)],
}
);
6. 启动 qiankun
start();
二、子应用改造(son-pro、son-pro1)
1. 安装依赖
pnpm install vite-plugin-qiankun
2. 配置 Vite 插件(vite.base.ts)
在 vite.base.ts 中添加 qiankun 插件配置:
import qiankun from 'vite-plugin-qiankun';
export default defineConfig({
plugins: [
qiankun('son-pro', {
useDevMode: true
})
]
});
3. 配置入口文件(main.ts)
- 导入
renderWithQiankun、qiankunWindow、QiankunProps - 创建渲染函数
render - 使用
renderWithQiankun包装生命周期钩子 - 添加独立运行判断
import { renderWithQiankun, qiankunWindow, QiankunProps } from 'vite-plugin-qiankun/dist/helper';
let app: any = null;
function render(props = {}) {
const { container } = props as any;
app = createApp(App);
app.use(router);
app.use(createPinia());
app.mount(container ? container.querySelector('#app') : '#app');
}
renderWithQiankun({
mount(props) {
console.log('子应用:被主应用挂载', props);
props.onGlobalStateChange((state: Record<string, any>, prev: Record<string, any>) => {
console.log('子应用接收到全局状态:', state);
}, true);
render(props);
},
bootstrap() {
console.log('子应用:首次初始化');
},
unmount(props) {
console.log('子应用:被主应用卸载', props);
app.unmount();
app = null;
},
update: function (props: QiankunProps): void | Promise<void> {
throw new Error('Function not implemented.');
},
});
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render();
}
4. 配置路由(router/index.ts)
- 使用 Hash 模式路由
- 配置子应用的基础路径(base)
const router: Router = createRouter({
history: createWebHashHistory('#/son-pro'),
routes,
});
5. 配置打包输出(vite.prod.ts)
- 配置输出路径和文件命名规则
- 配置代码分割策略
rollupOptions: {
output: {
entryFileNames: 'son-pro/js/[name].[hash].js',
chunkFileNames: 'son-pro/js/[name].[hash].js',
assetFileNames: 'son-pro/[ext]/[name].[hash].[ext]',
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'element-plus': ['element-plus'],
axios: ['axios'],
'@vueuse/core': ['@vueuse/core'],
},
},
}
三、构建配置
1. 统一构建脚本(build.js)
根目录提供了统一的构建脚本,可以一次性构建所有项目:
node build.js
2. 单独构建
# 主应用
cd main-pro && pnpm run build
# 子应用
cd son-pro && pnpm run build
cd son-pro1 && pnpm run build
3. 开发环境启动
# 主应用(端口 9000)
cd main-pro && pnpm run dev
# 子应用1(端口 9001)
cd son-pro && pnpm run dev
# 子应用2(端口 9002)
cd son-pro1 && pnpm run dev
微前端改造注意事项
一、主应用注意事项
1. 端口配置
- 确保主应用和子应用使用不同的端口
- 主应用默认端口:9000
- 子应用端口:9001、9002 等
- 在 vite.dev.ts 中配置 server.port
2. 路由模式
- 主应用和子应用建议都使用相同模式路由
3. 容器挂载
- 确保在 App.vue 中创建了微应用挂载容器
- 容器 ID 必须与 registerMicroApps 中的 container 配置一致
4. 全局状态管理
- 使用
initGlobalState初始化全局状态 - 通过
setGlobalState更新状态 - 子应用通过
props.onGlobalStateChange监听状态变化
5. 生命周期钩子
- 合理使用生命周期钩子进行资源管理
- beforeLoad: 加载前
- beforeMount: 挂载前
- afterMount: 挂载后
- beforeUnmount: 卸载前
- afterUnmount: 卸载后
二、子应用注意事项
1. 独立运行能力
- 子应用必须能够独立运行和开发
- 通过
qiankunWindow.__POWERED_BY_QIANKUN__判断是否在 qiankun 环境中 - 独立运行时直接调用 render 函数
2. 生命周期管理
- mount: 挂载时调用,接收主应用传递的 props
- bootstrap: 初始化时调用,只执行一次
- unmount: 卸载时调用,需要清理资源
- update: 更新时调用(可选)
3. 路由配置
- 子应用路由必须配置 base 路径
- base 路径必须与主应用的 activeRule 一致
- 例如:
createWebHashHistory('#/son-pro')
4. 资源导出
- 使用
vite-plugin-qiankun插件 - 在 vite.base.ts 中配置插件
- 确保子应用能够导出生命周期函数
5. 样式隔离
- qiankun 默认开启样式隔离
- 避免使用全局样式
- 使用 scoped 或 CSS Modules
6. JS 沙箱
- qiankun 提供了 JS 沙箱机制
- 避免修改全局变量
- 使用闭包封装私有变量
三、通信注意事项
1. 主应用向子应用传递数据
- 通过 props 传递数据
- 子应用在 mount 生命周期中接收
mount(props) {
console.log('接收到的 props:', props);
}
2. 子应用向主应用传递数据
- 通过全局状态管理
- 子应用调用
props.setGlobalState
props.setGlobalState({
token: 'new-token',
userInfo: { name: '李四' }
});
3. 子应用间通信
- 通过主应用作为中介
- 子应用 A 更新全局状态
- 子应用 B 监听状态变化
项目结构
qk/
├── main-pro/ # 主应用
│ ├── src/
│ │ ├── api/ # API 接口
│ │ ├── axios/ # Axios 配置
│ │ ├── router/ # 路由配置
│ │ ├── stores/ # 状态管理
│ │ ├── views/ # 页面组件
│ │ ├── App.vue # 根组件
│ │ └── main.ts # 入口文件
│ ├── vite.base.ts # Vite 基础配置
│ ├── vite.dev.ts # Vite 开发配置
│ ├── vite.prod.ts # Vite 生产配置
│ └── package.json
├── son-pro/ # 子应用1
│ ├── src/
│ │ ├── api/
│ │ ├── axios/
│ │ ├── router/
│ │ ├── stores/
│ │ ├── views/
│ │ ├── App.vue
│ │ └── main.ts
│ ├── vite.base.ts
│ ├── vite.dev.ts
│ ├── vite.prod.ts
│ └── package.json
├── son-pro1/ # 子应用2
│ ├── src/
│ │ ├── api/
│ │ ├── axios/
│ │ ├── router/
│ │ ├── stores/
│ │ ├── views/
│ │ ├── App.vue
│ │ └── main.ts
│ ├── vite.base.ts
│ ├── vite.dev.ts
│ ├── vite.prod.ts
│ └── package.json
├── build.js # 统一构建脚本
└── nginx.conf # Nginx 配置