前言
最近在做项目重构的事情,原来的一个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文件的问题。