第一次提交
This commit is contained in:
19
jeecgboot-vue3/src/utils/monorepo/dynamicRouter.ts
Normal file
19
jeecgboot-vue3/src/utils/monorepo/dynamicRouter.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export type DynamicViewsRecord = Record<string, () => Promise<Recordable>>;
|
||||
|
||||
/** 已注册模块的动态页面 */
|
||||
export const packageViews: DynamicViewsRecord = {};
|
||||
|
||||
/**
|
||||
* 注册动态路由页面
|
||||
* @param getViews 获取该模块下所有页面的方法
|
||||
*/
|
||||
export function registerDynamicRouter(getViews: () => DynamicViewsRecord) {
|
||||
if (typeof getViews === 'function') {
|
||||
let dynamicViews = getViews();
|
||||
Object.keys(dynamicViews).forEach((key) => {
|
||||
// 处理动态页面的key,使其可以让路由识别
|
||||
let newKey = key.replace('./src/views', '../../views');
|
||||
packageViews[newKey] = dynamicViews[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
134
jeecgboot-vue3/src/utils/monorepo/registerPackages.ts
Normal file
134
jeecgboot-vue3/src/utils/monorepo/registerPackages.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import type { App } from 'vue';
|
||||
import { warn } from '/@/utils/log';
|
||||
import { registerDynamicRouter } from '/@/utils/monorepo/dynamicRouter';
|
||||
import { add } from '/@/components/Form/src/componentMap';
|
||||
|
||||
// 懒加载模块配置(按需加载,访问相关路由时才加载对应包)
|
||||
const lazyPackages = [
|
||||
{ name: '@jeecg/online', importer: () => import('@jeecg/online') },
|
||||
{ name: '@jeecg/aiflow', importer: () => import('@jeecg/aiflow') },
|
||||
];
|
||||
|
||||
let appInstance: App | null = null;
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
const installOptions = {
|
||||
baseImport,
|
||||
};
|
||||
|
||||
export function registerPackages(app: App) {
|
||||
// 仅保存 app 实例,不立即加载模块
|
||||
appInstance = app;
|
||||
}
|
||||
|
||||
/** 已加载的包缓存 */
|
||||
const loadedPackages = new Map<string, any>();
|
||||
/** 正在加载的包 Promise 缓存(防止重复加载) */
|
||||
const loadingPromises = new Map<string, Promise<any>>();
|
||||
|
||||
/**
|
||||
* 按需加载包并注册
|
||||
*/
|
||||
async function ensurePackageLoaded(pkgConfig: typeof lazyPackages[number]) {
|
||||
const { name, importer } = pkgConfig;
|
||||
if (loadedPackages.has(name)) {
|
||||
return loadedPackages.get(name);
|
||||
}
|
||||
if (!loadingPromises.has(name)) {
|
||||
const promise = importer().then((pkg) => {
|
||||
const mod = pkg.default || pkg;
|
||||
if (appInstance) {
|
||||
appInstance.use(mod, installOptions);
|
||||
registerDynamicRouter(mod.getViews);
|
||||
}
|
||||
loadedPackages.set(name, mod);
|
||||
loadingPromises.delete(name);
|
||||
return mod;
|
||||
});
|
||||
loadingPromises.set(name, promise);
|
||||
}
|
||||
return loadingPromises.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 component 路径关键字匹配优先加载的包
|
||||
*/
|
||||
function getMatchedPackage(component: string): typeof lazyPackages[number] | null {
|
||||
const lc = component.toLowerCase();
|
||||
for (const pkgConfig of lazyPackages) {
|
||||
// 从包名中提取关键字,如 @jeecg/online -> online, @jeecg/aiflow -> aiflow
|
||||
const keyword = pkgConfig.name.split('/').pop()!;
|
||||
if (lc.includes(keyword)) {
|
||||
return pkgConfig;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定包中查找组件
|
||||
*/
|
||||
async function findComponentInPackage(pkgConfig: typeof lazyPackages[number], component: string): Promise<(() => Promise<Recordable>) | null> {
|
||||
try {
|
||||
const mod = await ensurePackageLoaded(pkgConfig);
|
||||
const views = mod.getViews();
|
||||
for (const key of Object.keys(views)) {
|
||||
const k = key.replace('./src/views', '');
|
||||
const startFlag = component.startsWith('/');
|
||||
const endFlag = component.endsWith('.vue') || component.endsWith('.tsx');
|
||||
const startIndex = startFlag ? 0 : 1;
|
||||
const lastIndex = endFlag ? k.length : k.lastIndexOf('.');
|
||||
if (k.substring(startIndex, lastIndex) === component) {
|
||||
return views[key];
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 包不存在或加载失败,跳过
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按需加载包组件:当路由匹配不到本地组件时调用
|
||||
* 根据 component 路径中的关键字优先匹配对应包,避免无意义的遍历
|
||||
*/
|
||||
export async function loadPackageComponent(component: string): Promise<(() => Promise<Recordable>) | null> {
|
||||
// 优先根据关键字精准匹配包
|
||||
const matched = getMatchedPackage(component);
|
||||
if (matched) {
|
||||
return findComponentInPackage(matched, component);
|
||||
}
|
||||
// 未匹配到关键字,依次尝试所有包
|
||||
for (const pkgConfig of lazyPackages) {
|
||||
const result = await findComponentInPackage(pkgConfig, component);
|
||||
if (result) return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 模块里可使用的import
|
||||
const importGlobs = [import.meta.glob('../../utils/**/*.{ts,js,tsx}'), import.meta.glob('../../hooks/**/*.{ts,js,tsx}')];
|
||||
|
||||
/**
|
||||
* 基础项目导包
|
||||
* 目前支持导入如下
|
||||
* /@/utils/**
|
||||
* /@/hooks/**
|
||||
*
|
||||
* @param path 文件路径,ts无需输入后缀名。如:/@/utils/common/compUtils
|
||||
*/
|
||||
async function baseImport(path: string) {
|
||||
if (path) {
|
||||
// 将 /@/ 替换成 ../../
|
||||
path = path.replace(/^\/@\//, '../../');
|
||||
for (const glob of importGlobs) {
|
||||
for (const key of Object.keys(glob)) {
|
||||
if (path === key || `${path}.ts` === key || `${path}.tsx` === key) {
|
||||
return glob[key]();
|
||||
}
|
||||
}
|
||||
}
|
||||
warn(`引入失败:${path} 不存在`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user