qiankun
主应用 main + 两个微应用 app-1、app-2,均基于 Vite + Vue3 + Element-plus
源码包含动态路由,结合 Apifox 进行 mock 数据 源码已上传
本博客代码,仅实现 qiankun 微前端路由访问功能,很简约
效果

主应用 main
sh
yarn add qiankun需要改造的文件
ts
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: '/about',
name: 'about',
component: () => import('@/views/AboutView.vue'),
},
{
// history模式需要通配所有路由,详见vue-router文档
path: '/app/app-1/:pathMatch(.*)*',
name: 'app-1',
component: () => import('@/components/SubContainer.vue'),
},
{
path: '/app/app-2/:pathMatch(.*)*',
name: 'app-2',
component: () => import('@/components/SubContainer.vue'),
},
],
})
export default routervue
<script setup lang="ts">
import { onMounted } from 'vue'
import { registerMicroApps, start } from 'qiankun'
onMounted(() => {
if (!(window as any).qiankunStarted) {
;(window as any).qiankunStarted = true
registerMicroApps([
{
name: 'app-1',
entry: '//localhost:1111',
container: '#sub-container',
activeRule: '/app/app-1',
},
{
name: 'app-2',
entry: '//localhost:2222',
container: '#sub-container',
activeRule: '/app/app-2',
},
])
start({
sandbox: {
experimentalStyleIsolation: true, // 样式隔离
},
})
}
})
</script>
<template>
<div id="sub-container"></div>
</template>微应用 app-1 (app-2 同)
注意
qiankun 官网告知 vue 3 版本等稳定后再补充支持,目前无法获取 window.__POWERED_BY_QIANKUN__ 等,此处基于社区插件 vite-plugin-qiankun
sh
yarn add vite-plugin-qiankun需要改造的文件
ts
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import {
renderWithQiankun,
qiankunWindow,
type QiankunProps,
} from 'vite-plugin-qiankun/dist/helper'
/**
* @description 注意!每次执行路由,都要createApp一次,否则警告:
* @description [Vue warn]: App has already been mounted.
* @description If you want to remount the same app, move your app creation logic into a factory function and create fresh app instances for each mount - e.g. `const createMyApp = () => createApp(App)
* */
let app: any = null
const render = ({ container }: any) => {
// 如果是在主应用的环境下就挂载主应用的节点,否则挂载到本地
const appDom = container ? container : '#app'
app = createApp(App)
app.use(createPinia()).use(router)
app.mount(appDom)
}
const initQiankun = () => {
renderWithQiankun({
// bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap
bootstrap() {
console.log('bootstrap')
},
// 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法,也可以接受主应用传来的参数
mount(_props: any) {
console.log(
'%c%s',
'padding: 2px 10px;color: #fff; background: #67C23A',
'mount',
_props
)
render(_props)
},
// 应用每次 切出/卸载 会调用的unmount方法,通常在这里我们会卸载微应用的应用实例
unmount(_props: any) {
console.log(
'%c%s',
'padding: 2px 10px;color: #fff; background: #F56C6C',
'unmount',
_props
)
const appDom = _props.container ? _props.container : '#app'
app.unmount(appDom)
},
update: function (props: QiankunProps): void | Promise<void> {
console.log('update')
},
})
}
qiankunWindow.__POWERED_BY_QIANKUN__ ? initQiankun() : render({})ts
import { defineConfig } from 'vite'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig(({ command, mode }) => {
return {
plugins: [
vue(),
qiankun('app-1', {
useDevMode: true,
}),
],
// ...
}
})ts
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-1'
: import.meta.env.BASE_URL
),
routes: [
{
path: '/home',
name: 'home',
component: () => import('../views/HomeView.vue'),
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue'),
},
],
})
export default router
Zhan's Blog