Umi + qiankun 實現動態載入子應用路由

恪晨發表於2022-05-11

前言

  最近在做專案重構的事情,原來的一個Vue專案有幾十個選單,專案大的令人髮指,所以準備重構,使用了umi+qiankun的方式,子應用使用了vue和react兩個型別的框架。

需求

  因為用到了umi框架,預設的路由檔案統一配置在config/routers下面,並且是靜態的,但是因為現在是動態新增的子應用,如果使用靜態的路由檔案,每次新加一個子應用,就需要修改一次主應用中的路由檔案再發布一次,明顯感覺不合理。因此找了一個解決動態路由的方法,也是官方的解決方案。配置的方式主要是在執行時進行,官方檔案見https://umijs.org/zh-CN/docs/runtime-config

配置

  • 第一步:獲取子應用配置列表
      因為涉及使用到微應用的配置方式,所以首先是在app.ts中呼叫介面獲取微應用的資訊列表

    // 後面需要使用
    let globalApp: any[] = [];
    // 獲取微應用資訊列表
    export const qiankun = getApps().then((data) => {
      const apps = data?.DATA.filter((i: { entry: any }) => i.entry) || [];
    
      const tmp = apps?.map((app: any) => {
          return {
              ...app,
              // 增加一些子應用需要用到變數
              props: {
                  globalState: {
                      ...initState,
                  },
              },
          };
      });
      globalApp = tmp;
      return {
          apps: tmp,
      };
    });
    
    // 返回的資料結構
    const response = [
      {
          enrty: 'https://10.10.10.10:111',
          name: 'microApp1'
      },
      {
          enrty: 'https://10.10.10.10:222',
          name: 'microApp2'
      }
    ];
  • 第二步:在app.ts中新增路由配置
      同樣還是在app.ts中,新增patchRoutes配置,這個主要功能是為了動態增加新的路由,主要功能也是利用這個實現的,具體程式碼如下。這裡的extraRoutes是提前定義好的變數,用於儲存從介面拿到的資料,forEach裡面的router[0]這些是根據自己的路由配置,找到具體要新增新的路由的位置,並塞進去一個路由配置。

    let extraRoutes: object[] = [];
    export function patchRoutes({ routes }: any) {
      extraRoutes.forEach((element: any) => {
          routes[0].routes[2].routes[0].routes.unshift({
              name: element.name,
              path: element.path,
              component: dynamic({
                  loader: () =>
                      import(
                          /* webpackChunkName: 'layouts__MicroAppLayout' */ '@/layouts/MicroAppLayout'
                      ),
                  loading: LoadingComponent,
              }),
          });
      });
    }
  • 第三步:新增一個微應用元件
      上面第二步中我們新增加一個路由的時候使用到了component欄位,本來如果使用靜態路由方式的話,我們可以在config/routes中可以直接新增一條靜態路由如{name: 'microApp3', path: '/microApp3', microApp: 'microApp3'}這樣子,但是使用動態方式時卻不能直接push這麼一條,會不生效,所以需要使用component的方式,因此這裡使用了<MicroApp></MicroApp>的方式新增的。
      我們在layouts資料夾下面新建一個檔名稱叫MicroAppLayout.tsx,內容如下,相當於把它封裝成了一個元件,並通過dynamic動態引入,name也會通過props自動傳入,這樣我們會在第二步中迴圈獲取到的子應用列表將element.name傳入進去即可。

    import React from 'react';
    import { MicroApp } from 'umi';
    
    const MicroAppLayout: React.FC = (props: any) => {
      return (
          <>
              <MicroApp name={props?.route?.name} />
          </>
      );
    };
    export default MicroAppLayout;
  • 第四步:渲染新的路由
      通過以上的方式,我們就已經動態的將路由配置進行了更新,並且適配了微應用,接下來只需要重新render一下就好了,在app.ts中新增如下程式碼,globalApp就是上面通過介面獲取到的微應用列表,map之後賦值給extraRoutes,再通過oldRender重新渲染即可。

    export function render(oldRender: () => void) {
      extraRoutes = globalApp?.map((app: any) => {
          return {
              name: app.name,
              path: '/' + app.name,
          };
      });
      oldRender();
    }

    總結

      通過以上的方式,我們就能根據後端的返回介面,動態的新增路由了,本地的路由配置檔案只需要配置一些主應用常用的並且幾乎不會變化的路由即可。當然不光是微應用可以使用這種方式,如果有需要的話普通的路由也可以使用這種方式進行配置,這也就省去了我們每次新加一個選單就要更新一遍routers檔案的問題。

參考

https://blog.csdn.net/BLUE_JU...

相關文章