乾坤-微前端改造

71 阅读5分钟

微前端改造总结

乾坤-微前端改造 (gitee.com)

项目概述

本项目是一个基于 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 的 registerMicroAppsstartinitGlobalState
  • 初始化全局状态管理
  • 创建 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)
  • 导入 renderWithQiankunqiankunWindowQiankunProps
  • 创建渲染函数 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 配置