vue3+vite项目接入qiankun微前端的核心配置项
最近在研究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微前端的关键要点啦。大伙在实际项目中遇到问题,欢迎一起讨论,互相学习!