场景:
1. 接入三个主应用的路由信息:
(1)http://xxx/sports/project/item;
(2)http://xxx/medical/project/item;
(3)http://xxx/education/project/item。
2. 接口信息:
(1)http://xxx/sports/projectApi/xxx;
(2)http://xxx/medical/projectApi/xxx;
(3)http://xxx/education/projectApi/xxx;
3. publicPath路径(在浏览器看index.json):
(1)http://xxx/sports/projectApp/index.json;
(2)http://xxx/medical/projectApp/index.json;
(3)http://xxx/education/projectApp/index.json;
如果要在脚本里面配置前缀信息,就需要在package.json里面进行配置:
// 拿sports做个案例(sports是hash路由,如果是history路由,不需要加HISTORY=hash)
"scripts":{
"bulid:sports": "cross-env PUBLIC_PATH_PREFIX=sports HISTORY=hash umi build",
"start:sports": "cross-env UMI_ENV=dev HISTORY=hash PUBLIC_PATH_PREFIX=sports umi dev"
}
// 如果要在本地启动这个应用,需要输入命令yarn start:sports才能获取到对应的PUBLIC_PATH_PREFIX
先在config.ts里面配置publicPath的路径:
// config.ts
// 配置同一个路径方便后面部署的时候共用同一个流水线
// medical是第一个子应用就配置好了的(sports和education是后来需要接入的项目,所以一开始的路由就以medical为主)
const publicPath = PUBLIC_PATH_PREFIX=== 'sports'? `/${PUBLIC_PATH_PREFIX}/medical/projectApp/`:`/medical/projectApp/`
处理动态路由的方法:
先在routes.ts里面把共同的路由设置一下,就是这三个应用路由的共同部分作为这个子应用的路由信息,然后在BasicLayout.js里面去写动态配置路由的方法:
// BasicLayout.ts
// 在各个主应用里面可以先存储一下前缀信息
const prefix = sessionStorage.getItem('prefix') || '';
// 通过获取路由信息进行动态更换前缀
const paths = window.location.pathname.split('/');
const hashPath = window.location.hash.replace('#','')?.split('/') || [];
let targetPaths = '/';
let urlPrefix = '/';
// 处理路径与组件对应
if(paths.indexOf(BaseSettings.appName) > -1){
targetPaths += paths.splice(paths.indexOf(BaseSettings.appName)).join('/');
urlPrefix = paths.join('/');
sessionStorage.setItem('api-prefix', urlPrefix);
} else if(hashPath.indexOf(BaseSettings.appName) > -1){
// 兼容hash加载的情况
targetPaths += hashPath.splice(hashPath.indexOf(BaseSettings.appName)).join('/');
urlPrefix = hashPath.join('/');
// 兼容主应用hash前缀
sessionStorage.setItem('api-prefix', prefix);
}
const { children } = props;
if(children?.props?.location){
// 下面一行做判断的原因是当hash路由拼接了query参数时,匹配不到routes.ts里的路由,导致页面跳转是空白,所以得先把query参数去掉去匹配到正确的路由才能正常跳转
children?.props?.location.pathname = targetPaths.includes('?') ? targetPaths.split('?')[0] : targetPaths
}
接下来就是在apiCreator.js配置接口前缀:
// apiCreator.js
// 这个方法就用于调用接口时的路径
const padPrefix = url => {
const apiPrefix = `/${sessionStorage.getItem('prefix')}/${BaseSettings.appName}Api`;
if(url.indexOf(apiPrefix) === -1){
return apiPrefix + url;
}
return url;
}
get(url, query) {
let finalUrl = padPrefix(url);
const queryString = _isEmpty(query) ? '' : queryToString(query);
...
}
需要配置hash路由时,要动态配置一下hash
// config.ts
runtimeHistory: {},
// app.tsx
import { setCreateHistoryOptions } from 'umi';
if(sessionStorage.getItem('prefix') === 'sports'){
setCreateHistoryOptions({
type: 'hash',
});
}