vue3+vite项目接入qiankun微前端关键点

主应用

1. 增加匹配所有子路由通配路由

ts 复制代码
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'),
  },
];

2. 注册、启动子路由

  • #/views/sub-app/index.vue
html 复制代码
// #/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>
  • 注册:#/components/micro-app
ts 复制代码
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', // app name registered  
        entry: `//${window.location.hostname}:${import.meta.env.VITE_DIGITAL_TWIN_PORT}${import.meta.env.VITE_BASE}digital-twin/`,  
        container: '#digital-twin',
        activeRule: `${import.meta.env.VITE_BASE}digital-twin`,  
        props: {  
          actions: microAppActions,  
          excludeAssetFilter: (assetUrl: string) => {  
            // 排除 Vite 插入的热更新脚本  
            return assetUrl.includes('@react-refresh');  
          },  
        },  
      },  
    ]);  
  
    // 监听子应用,登录失效消息
    microAppActions.onGlobalStateChange((state, prev) => {  
      if (!state.isLogin && state.isLogin !== prev.isLogin) {
         useAuthStore().logout();
      }
    });
    return () => null;
  },
});
       
  • 启动:./useSubapp
ts 复制代码
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,  
      });  
    }  
    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);
    });
  });
};
  

注意: 1. 子应用挂载节点不要选择和主应用一样的节点(#app), 或者包含主应用(vue3) router-view组件的dom节点,否则会出现子应用返回主应用时,主应用路由失效,页面空白的问题

子应用

1. 安装qiankun vite插件

bash 复制代码
 npm i  vite-plugin-qiankun -S

2. 在vite.config.ts中引用

ts 复制代码
export default defineConfig(({ mode }) => {
    ...
    return {
        ...
        plugins: [
          react(),
          // 引用插件
          qiankun('twinplatform', {
            // 子应用名称
            useDevMode: true, // 开发模式下启用
          }),
        ]
        ...
    }
}

3. 改造子应用入口文件

ts 复制代码
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 />);
};


const lifecycle: QiankunLifeCycle = {
  mount(props: QiankunProps): void {
    // 实现 mount 逻辑
    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(lifecycle);

// 3. 独立运行逻辑
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
  render();
}

注意:1. 必须要使用插件的,renderWithQiankun方法,否则会提示无法找到入口声明周期钩子函数

其他注意点:

主应用,子应用路由匹配、路由前缀、服务前缀

  1. 子应用和主应用的服务前缀要保持一致,例如著应用服务前缀为:a/b, 则子应用的服务前缀也要包含:a/b, eg:
js 复制代码
// history模式

子应用地址: localhost:8666/a/b/home

主应用地址:localhost:8999/a/b/child-sub1/home

// 子应用必须包含主应用的服务前缀,否则registerMicroApps注册的子应用激活规则:activeRule: `child-sub1`,无法正常配置激活子应用
// 必须要写成:activeRule: `{主应用服务前缀}/child-sub1`
  1. 如果有服务前缀,需同步设置路由的baseurl:
ts 复制代码
// 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,
});
  1. 主应用,子应用路由模式要保持一致,histroy或者hash

  2. 解决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,否则会出在子应用页面刷新,丢失主应用问题, 建议最好主应用和子应用部署在同一个域名下

相关推荐
Dontla16 分钟前
黑马node.js教程(nodejs教程)——AJAX-Day01-04.案例_地区查询——查询某个省某个城市所有地区(代码示例)
前端·ajax·node.js
威哥爱编程18 分钟前
vue2和vue3的响应式原理有何不同?
前端·vue.js
呆呆的猫21 分钟前
【前端】Vue3 + AntdVue + Ts + Vite4 + pnpm + Pinia 实战
前端
qq_4560016523 分钟前
30、Vuex 为啥可以进行缓存处理
前端
浪裡遊44 分钟前
Nginx快速上手
运维·前端·后端·nginx
天生我材必有用_吴用1 小时前
Vue3后台管理项目封装一个功能完善的图标icon选择器Vue组件动态加载icon文件下的svg图标文件
前端
小p1 小时前
初探typescript装饰器在一些场景中的应用
前端·typescript·nestjs
晓得迷路了1 小时前
栗子前端技术周刊第 72 期 - 快 10 倍的 TypeScript、React Router 7.3、Astro 5.5...
前端·javascript·typescript
xiaoyan20151 小时前
vue3仿Deepseek/ChatGPT流式聊天AI界面,对接deepseek/OpenAI API
前端·vue.js·deepseek
加个鸡腿儿1 小时前
D老师:如何正确控制图片尺寸?父容器设置为何失效?
前端·css