mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-03-26 23:33:13 +00:00
135 lines
4.1 KiB
Vue
135 lines
4.1 KiB
Vue
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;
|
||
}
|