qiankun + vite 实现Vue3项目微服务基本搭建

1,369 阅读4分钟

前言

  • 主应用和微应用技术栈都是vue3+vite
  • 主应用需要安装qiankun插件
  • 微应用需要安装vite-plugin-qiankun插件

主应用相关操作

安装 npm i qiankun -S 插件

新建文件夹(qiankun)

在src目录下面新建一个qiankun的文件夹,存放qiankun相关的文件,方便后续的管理和查找。

主文件

在qiankun文件夹里面新建main.js文件。文件内容如下:

import { registerMicroApps } from 'qiankun'

// 导入所有的微应用
import subAppConfig from '@/qiankun/subAppConfig' // 微应用的配置文件的路径

const { subApps } = subAppConfig

export function registerApps() {
  try {
    registerMicroApps(subApps, {
      beforeLoad: [
        (app) => {
          console.log('before load', app)
        },
      ],
      beforeMount: [
        (app) => {
          console.log('before mount', app)
        },
      ],
      afterUnmount: [
        (app) => {
          console.log('before unmount', app)
        },
      ],
    })
  } catch (err) {
    console.log(err)
  }
}


容器配置(用于渲染微应用)

新建一个src/components/SubContainer.vue组件,用于存放微应用。

<template>
  <!-- 容器的id。微应用配置的时候需要 -->
  <div id="sub-container"></div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'
import { start } from 'qiankun'
// 引入qiankun
import { registerApps } from '@/qiankun/main.js' // qiankun主文件的路径

onMounted(() => {
  if (!window.qiankunStarted) {
    window.qiankunStarted = true
    registerApps()
    // 开启qiankun
    start({
      // sandbox: {
      //   // sandbox: { strictStyleIsolation: true } // 严格隔离
      //   // experimentalStyleIsolation: true // 样式隔离
      // }
    })
  }
})
</script>

微应用配置文件

在qiankun文件夹里面新建subAppConfig.js。存放子应用配置,可以配置多个子应用。

const subApps = [
  {
    name: 'SubAppName', // 子应用名称,保持唯一性。在微应用中会使用到。
    container: '#sub-container', // 微应用挂载的容器的id。   SubContainer组件中声明的id名
    activeRule: '/app/app-vue3', // 主应用响应的路由信息。 即当访问到这个路由下面的路由,都是微应用的路由。router.js文件配置的path
    entry: '//localhost:7788', // 子应用网址。 本地环境下指定端口。当主应用匹配到activeRule时,会被转发到当前设置的链接下面。
    props: {}, // 主应用与子应用通信传值
  },
]

export default {
  subApps,
}

参考图片 更好理解

image.png

配置router文件

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: () => import('@/views/HomeView.vue'),
    },
    {
      path: '/table',
      name: 'table',
      component: () => import('@/views/TableView.vue'),
    },
    {
      path: '/table2',
      name: 'table2',
      component: () => import('@/views/TableView.vue'),
    },
    {
      path: '/table3',
      name: 'table3',
      component: () => import('@/views/TableView.vue'),
    },
    {
      // history模式需要通配所有路由,详见vue-router文档
      path: '/app/app-vue3/:pathMatch(.*)*',
      name: 'app-vue3',
      meta: {},
      // 微应用组件的容器
      component: () => import('@/components/SubContainer.vue'),
    },
  ],
})

export default router

启动项目,正常打开页面。访问结束。

微应用

安装 npm i vite-plugin-qiankun -S 插件

vite.config.js里面配置qiankun

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// import vueDevTools from 'vite-plugin-vue-devtools'
import qiankun from 'vite-plugin-qiankun'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // vueDevTools(),
    qiankun(
      'SubAppName', // 主应用里面配置的微应用的name
      {
        useDevMode: true,
      },
    ),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
  server: {
    port: 7788,
    open: false,
  },
})

history模式,修改一下router文件

import { createRouter, createWebHistory } from 'vue-router'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'

const router = createRouter({
  history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/app/app-vue3/' : '/'),
  routes: [
    {
      path: '/',
      name: 'home',
      component: () => import('@/views/HomeView.vue'),
    },
    {
      path: '/table',
      name: 'table',
      component: () => import('@/views/TableView.vue'),
    },
    {
      path: '/table2',
      name: 'table2',
      component: () => import('@/views/TableView.vue'),
    },
    {
      path: '/table3',
      name: 'table3',
      component: () => import('@/views/TableView.vue'),
    },
  ],
})

export default router


main.ts中引入配置qiankun

import './assets/reset.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css'

import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'

import router from './router'

import Layout from './components/layout/index.vue'

let app = null

const render = (container) => {
  app = createApp(Layout)
  app.use(createPinia())
  app.use(router)
  app.use(Antd)
  app.mount(container ? container.querySelector('#app') : '#app')
}

const initQianKun = () => {
  renderWithQiankun({
    mount(props) {
      const { container } = props
      render(container)
    },
    bootstrap() {},
    unmount() {
      app.unmount()
    },
  })
}

qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()


启动项目,运行没问题。

两者访问

微应用 http://localhost:7788
主应用 http://localhost:6677
修改主应用的菜单

image.png 当点击sub app菜单时,即访问了http://localhost:6677/app/app-vue3/table2
根据qiankun配置的activeRule,相当于访问了http://localhost:7788/table2
只不过访问的这个地址会以组件的形式在主应用渲染,因为微应用配置文件中配置了挂载的组件id

image.png 通过上面的图可以看到,微应用的页面被渲染到了SubContainer组件里面

微应用菜单栏的处理

当我们什么也不做的时候,会把整个微应用的页面渲染到主应用的内容区域

image.png 如图,其实我们只是想要微应用的内容区域。需要去除图中红色的部分。
解决方案: 修改微应用中的布局文件

image.png 通过qiankunWindow.POWERED_BY_QIANKUN 来判断当前是否在主应用下,动态渲染布局文件

tips

qiankun官网

image.png
当主应用在访问子应用的路由时,子应用关闭,会出现如上错误。子应用访问不到

关于路由选择

主应用路由微应用路由特殊设置
historyhistory微应用需要设置 base。eg: history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/app/app-vue3/' : '/'),
historyhash无设置
hashhistoryactiveRule 前面加个#(但是不推荐这种方案)
hashhashactiveRule 前面加个#。 另外需要改写微应用的路由结构,在外面嵌套一层。嵌套的外层就是主应用设置的路径