章
目
录
最近在研究vue3+vite项目接入qiankun微前端的相关内容,踩过不少坑,也总结了一些经验。今天就来给大伙分享一下这里面的关键知识点,希望能帮到正在做类似项目的小伙伴们。
一、主应用配置
(一)添加匹配子路由的通配路由
在主应用里,咱们得配置能匹配所有子路由的通配路由。代码长这样:
const routes: RouteRecordRaw[] = [
{
path: '/digital-twin/:pathMatch(.*)*', // 子路由都以/digital-twin/ 这个前缀开头
name: 'DigitalTwin',
meta: {
icon: 'ic:baseline-view-in-ar',
keepAlive: true,
order: 1000,
title: $t('platform.route.digitalTwinPlatform'),
getTabTitle: createGetTabTitle('/digital-twin')
},
component: () => import('#/views/sub-app/index.vue')
}
];
这里的path
配置很关键,它表示所有以/digital-twin/
开头的路由都会匹配到这个规则,然后会加载对应的组件。
(二)注册和启动子路由
- 注册子应用:在
#/views/sub-app/index.vue
文件里,咱们来注册子应用。代码如下:
// #/views/sub-app/index.vue
<script lang="ts" setup>
import { updatePreferences } from '@vben/preferences';
import { MicroApp } from '#/components/micro-app';
import BasicLayout from '#/layouts/basic.vue';
import { useSubApp } from './useSubapp';
// 判断当前是不是全屏模式
const route = useRoute();
const isFullScreen = computed(() => route.query?.fullScreen === '1');
// 启动子应用
useSubApp();
</script>
<template>
<!-- 注册子应用的地方 -->
<MicroApp />
<div v-if="isFullScreen" class="sub-app">
<!-- 全屏预览时子应用的挂载节点,这种情况下不需要菜单和顶栏 -->
<div id="digital-twin"></div>
</div>
<BasicLayout v-else>
<template #subAppCounaner>
<div class="sub-app">
<!-- 正常情况下子应用的挂载节点,需要菜单和顶栏 -->
<div id="digital-twin"></div>
</div>
</template>
</BasicLayout>
</template>
<style lang="scss">
.sub-app {
height: calc(100vh - var(--vben-header-height) - var(--vben-footer-height));
overflow: hidden;
}
#digital-twin {
img {
display: inline-block;
}
}
</style>
这里的<MicroApp>
组件就是用来注册子应用的,它会根据后续的配置去加载子应用。
再看看#/components/micro-app
里的注册逻辑:
import { registerMicroApps } from 'qiankun';
import { useAuthStore } from '#/store/auth';
import { microAppActions } from './micro-app-actions';
export const MicroApp = defineComponent({
name: 'MicroApp',
setup() {
registerMicroApps([
{
name: 'twinplatform', // 给子应用取个名字,用于注册
// 子应用的入口地址,这里根据环境变量动态生成
entry: `//${window.location.hostname}:${import.meta.env.VITE_DIGITAL_TWIN_PORT}${import.meta.env.VITE_BASE}digital-twin/`,
container: '#digital-twin', // 子应用挂载到id为digital-twin的节点上
activeRule: `${import.meta.env.VITE_BASE}digital-twin`,
props: {
actions: microAppActions,
// 排除Vite插入的热更新脚本,避免影响子应用加载
excludeAssetFilter: (assetUrl: string) => assetUrl.includes('@react-refresh')
}
}
]);
// 监听子应用的登录状态变化
microAppActions.onGlobalStateChange((state, prev) => {
if (!state.isLogin && state.isLogin!== prev.isLogin) {
useAuthStore().logout();
}
});
return () => null;
}
});
这里通过registerMicroApps
方法注册了子应用,还配置了子应用的入口、挂载节点、激活规则等信息。同时,监听了子应用的登录状态变化,以便在登录失效时进行相应处理。
- 启动子应用:启动子应用的逻辑在
./useSubapp
文件里:
import {
onBeforeRouteUpdate,
type RouteLocationNormalizedLoadedGeneric,
useRoute
} from 'vue-router';
import { useTabbarStore } from '@vben/stores';
import { start } from 'qiankun';
export const useSubApp = () => {
const route = useRoute();
onMounted(() => {
if (!window.qiankunStarted) {
window.qiankunStarted = true;
console.log('start qiankun');
start({
sandbox: true
});
}
// 根据当前路由更新顶部tab标签
updateTabTitle(route);
});
// 更新顶部tab标签的函数
const updateTabTitle = (to: RouteLocationNormalizedLoadedGeneric) => {
const getTabTitle = to.meta.getTabTitle as (path: string) => string;
const title = getTabTitle(to.fullPath);
useTabbarStore().setTabTitle(to, title);
};
// 路由切换时同步更新顶栏tab标签
onBeforeRouteUpdate((to, from) => {
if (to.fullPath === from.fullPath) return;
setTimeout(() => {
updateTabTitle(to);
});
});
};
这里在页面挂载时启动qiankun,并且在路由变化时更新顶部的tab标签,保证用户体验。
还有个重要的点得注意:子应用的挂载节点可千万别选和主应用一样的节点(比如#app
),也别选包含主应用(vue3)router-view
组件的dom节点。不然,当子应用返回主应用时,主应用的路由可能会失效,页面就空白啦,这可就麻烦大了。
二、子应用配置
(一)安装和引用qiankun vite插件
- 安装插件:先在子应用项目里安装
vite-plugin-qiankun
插件,命令如下:
npm i vite-plugin-qiankun -S
- 在vite.config.ts中引用插件:安装好之后,在
vite.config.ts
里引用它:
export default defineConfig(({ mode }) => {
...
return {
...
plugins: [
react(),
// 引用插件
qiankun('twinplatform', {
// 子应用名称
useDevMode: true // 开发模式下启用
})
]
...
}
}
这个插件能帮助咱们更方便地接入qiankun微前端,配置起来也比较简单。
(二)改造子应用入口文件
子应用的入口文件也得改造一下,代码如下:
import React from'react';
import ReactDOM from'react-dom/client';
import App from './App';
import 'antd/dist/antd.css';
import './index.less';
import { actions } from '@/utils/microAppEvent';
import { renderWithQiankun, qiankunWindow, QiankunLifeCycle, QiankunProps } from 'vite-plugin-qiankun/dist/helper';
let root: ReactDOM.Root;
// 渲染函数,用于渲染子应用
const render = () => {
const el = document.getElementById('root') as HTMLElement;
root = ReactDOM.createRoot(el);
root.render(<App />);
};
// 定义qiankun的生命周期函数
const lifecycle: QiankunLifeCycle = {
mount(props: QiankunProps): void {
// 实现mount逻辑,设置actions并渲染子应用
actions.setActions(props.actions);
render();
},
bootstrap(): void {
// 实现bootstrap逻辑,在控制台打印提示信息
console.log('react app bootstraped');
},
unmount(props): void {
// 实现unmount逻辑,卸载子应用
console.log('react app unmount');
root?.unmount();
},
update(props: QiankunProps): void {
// 实现update逻辑
}
};
// 使用renderWithQiankun方法启动子应用
renderWithQiankun(lifecycle);
// 独立运行逻辑,如果不是在qiankun环境下,直接渲染子应用
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render();
}
这里通过renderWithQiankun
方法来启动子应用,并且实现了qiankun的生命周期函数。注意,必须要用这个方法,不然会提示找不到入口生命周期钩子函数。
三、其他需要注意的地方
(一)路由和服务前缀问题
- 子应用和主应用的服务前缀得保持一致。比如说,主应用服务前缀是
a/b
,那子应用的服务前缀也得包含a/b
。像这样:
// history模式
// 子应用地址:localhost:8666/a/b/home
// 主应用地址:localhost:8999/a/b/child-sub1/home
// 子应用必须包含主应用的服务前缀,不然registerMicroApps注册的子应用激活规则:activeRule: `child-sub1`,就没法正常配置激活子应用
// 必须写成:activeRule: `{主应用服务前缀}/child-sub1`
- 如果有服务前缀,还得同步设置路由的
baseurl
:
// react:
...
<BrowserRouter basename={服务前缀}>
...
</BrowserRouter>
...
// vue3
const router = createRouter({
history: `服务前缀`,
// 应该添加到路由的初始路由列表。
routes,
scrollBehavior: (to, _from, savedPosition) => {
if (savedPosition) {
return savedPosition;
}
return to.hash? { behavior:'smooth', el: to.hash } : { left: 0, top: 0 };
},
// 是否应该禁止尾部斜杠。
// strict: true,
});
(二)路由模式一致性
主应用和子应用的路由模式也得保持一致,要么都用history
模式,要么都用hash
模式。要是不一致,可能会出现各种奇怪的问题。
(三)解决history模式刷新404问题
在history
模式下,刷新页面可能会出现404错误。这时候可以通过nginx配置来解决,配置如下:
location /a/b {
try_files $uri $uri/ /a/b/index.html; # 找不到资源时,返回主应用首页
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';
}
这里要注意,子应用刷新时,别返回子应用的首页(index.html
),得返回主应用的index.html
。不然在子应用页面刷新时,可能会丢失主应用的内容。最好把主应用和子应用部署在同一个域名下,这样能减少很多麻烦。
以上就是vue3+vite项目接入qiankun微前端的关键要点啦。大伙在实际项目中遇到问题,欢迎一起讨论,互相学习!