vue3+vite项目接入qiankun微前端的核心配置项

前端 潘老师 1个月前 (03-17) 76 ℃ (0) 扫码查看

最近在研究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/开头的路由都会匹配到这个规则,然后会加载对应的组件。

(二)注册和启动子路由

  1. 注册子应用:在#/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方法注册了子应用,还配置了子应用的入口、挂载节点、激活规则等信息。同时,监听了子应用的登录状态变化,以便在登录失效时进行相应处理。

  1. 启动子应用:启动子应用的逻辑在./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插件

  1. 安装插件:先在子应用项目里安装vite-plugin-qiankun插件,命令如下:
npm i vite-plugin-qiankun -S
  1. 在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的生命周期函数。注意,必须要用这个方法,不然会提示找不到入口生命周期钩子函数。

三、其他需要注意的地方

(一)路由和服务前缀问题

  1. 子应用和主应用的服务前缀得保持一致。比如说,主应用服务前缀是a/b,那子应用的服务前缀也得包含a/b。像这样:
// history模式
// 子应用地址:localhost:8666/a/b/home
// 主应用地址:localhost:8999/a/b/child-sub1/home
// 子应用必须包含主应用的服务前缀,不然registerMicroApps注册的子应用激活规则:activeRule: `child-sub1`,就没法正常配置激活子应用
// 必须写成:activeRule: `{主应用服务前缀}/child-sub1`
  1. 如果有服务前缀,还得同步设置路由的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微前端的关键要点啦。大伙在实际项目中遇到问题,欢迎一起讨论,互相学习!


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/front/15913.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】