qiankun+vite+vue3从零搭建一个微前端架构系统

1,442 阅读4分钟

本文将记录一下从零搭建一个微前端架构系统,技术栈使用qiankun+vite+vue3,后面还会持续分享主应用与微应用通信,组件共享,性能优化等内容,因为qiankun官网没有介绍vite配置的方法,都是基于webpack的,我在使用vite搭建的时候踩了不少坑,也会记录分享在这里。

qiankun官网:介绍 - qiankun

参考网站:Micro Frontends

一、微前端架构介绍

微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 它具有如下特点:

  1. 技术栈无关。微应用可以是你喜欢的任意技术栈,Vue、React or Angular...
  2. 独立部署
  3. 独立运行。微应用之间状态隔离

image.png

二、项目搭建与准备

1. 创建主应用和子应用

  • 使用 vite 分别创建主应用项目和子应用项目。可以通过 npm create vue@latest 命令并按照提示进行相应配置来创建基础的 vite 项目。
  • 在主应用和子应用中安装 Element Plus(因为后续会用到,提前先配置好),在项目目录下执行 npm install element-plus,并且按需引入相关组件和样式(可通过自动导入插件等方式实现更便捷的引入)。
  • 在主应用中安装 qiankun,执行 npm install qiankun

2. 配置主应用

  • 在主应用的入口文件(main.ts)中,引入并注册 Element Plus 组件(假设采用按需引入方式,需先配置好自动导入插件如 unplugin-vue-components 和 unplugin-auto-import)。
  • 按照 qiankun 的要求配置主应用,主要包括注册子应用、设置生命周期等。

main.ts文件

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import { registerMicroApps, start } from 'qiankun'

const app = createApp(App)

app.use(router)
app.use(ElementPlus)

app.mount('#app')

registerMicroApps(
    [
        {
            name: 'silvia micro app', // app name registered
            entry: '//localhost:5174', // 微应用的出口地址
            container: '#container', // 微应用挂载的容器id
            activeRule: '/silvia-micro', // 微应用激活路由规则
        }
    ]
)

start()

App.vue文件(这里直接在vite创建的App.vue文件写展示子应用的代码)

<div class="wrapper">
     <HelloWorld msg="主应用" />
     <el-button>ss</el-button>
     <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/silvia-micro">Micro</RouterLink>
     </nav>
     <div id="container"></div>
</div>

3. 配置子应用

  • 这里遇到了vite搭建qiankun的两个坑(很重要!!!)
    1. 判断是否为独立运行时问题:官网中使用window.__POWERED_BY_QIANKUN__,但是在vite下运行后window下找不到__POWERED_BY_QIANKUN__, 后来经查阅发现vite要使用插件vite-plugin-qiankun,安装完成后,使用该插件提供的qiankunWindow.__POWERED_BY_QIANKUN__来判断。
    2. 子应用导出相应的生命周期问题:按照官网上导出子应用生命周期的方法,运行后发现在这里打印的log都没有出来,并且还报了个错,最后发现这里也需要vite-plugin-qiankun提供的导出方法renderWithQiankun image.png
  • webpack下的写法
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
    render();
}
export async function bootstrap() {
    console.log('[vue] vue app bootstraped');
}
export async function mount(props: QiankunProps | undefined) {
    console.log('[vue] props from main framework', props);
    render(props);
}
export async function unmount() {
    app.unmount();
}
  • vite下的写法!(既然我们使用vite搭建的,就得使用这种写法)
// 独立运行时
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
    render();
}

renderWithQiankun(
    {
        bootstrap: () => {
            console.log('[vue] vue app bootstraped');
        },
        mount: (props: QiankunProps) => {
            console.log('[vue] props from main framework', props);
            render(props);
        },
        unmount: (props: QiankunProps) => {
            window.console.log('unmount', props);
            app.unmount();
        },
        update: (props: QiankunProps) => {
            window.console.log('update');
        }
    }
)
  • index.html文件中修改挂载点:id需要改成'container'
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vite App</title>
  </head>
  <body>
    <div id="container"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

  • vite.config.ts中添加qiankun相关配置!(非常重要,否则微应用启动不起来):
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'

// https://vite.dev/config/
export default defineConfig({
    plugins: [
        vue(),
        qiankun('silvia-micro', { useDevMode: true }),
    ],
    resolve: {
        alias: {
            '@': fileURLToPath(new URL('./src', import.meta.url))
        },
    },
})

三、项目启动

  • 主应用和微应用都npm run dev image.png
  • 打开主应用url,然后点击Micro(我改了vite自动创建完成的按钮名称及跳转的path name),这里遇到了新的问题,微应用加载完又立即走了unmount生命周期

image.png 并且还报了died in status NOT_MOUNTED: Cannot read properties of undefined这样一个错,打断点跟了一下报错地方,发现原来是子应用没有配置路由。 image.png

image.png 修改微应用的main.ts文件,导入并挂载路由,完整的代码如下:

import App from './App.vue';
import { createApp } from 'vue';
import router from './router';

import { qiankunWindow, renderWithQiankun, type QiankunProps } from 'vite-plugin-qiankun/dist/helper';
let microRouter = null;
let app: any = null;
function render(props?: QiankunProps) {
    microRouter = router;
    app = createApp(App);
    app.use(microRouter)
    app.mount(props?.container ? props?.container.querySelector('#container') : '#container');
}

// 独立运行时
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
    render();
}

renderWithQiankun(
    {
        bootstrap: () => {
            console.log('[vue] vue app bootstraped');
        },
        mount: (props: QiankunProps) => {
            console.log('[vue] props from main framework', props);
            render(props);
        },
        unmount: (props: QiankunProps) => {
            window.console.log('unmount', props);
            app.unmount();
            microRouter = null;
        },
        update: (props: QiankunProps) => {
            window.console.log('update');
        }
    }
)
  • 接下来再刷新页面,发现不报错了,控制台log也按照我们预期的执行了

image.png

基础搭建先写到这里,后面会继续分享主应用与子应用通信方式,组件共享等内容,希望大家持续关注。