Skip to content

Commit c554c4c

Browse files
committed
@jeecg/online和@jeecg/aiflow库按需加载
1 parent 5bf8a04 commit c554c4c

File tree

4 files changed

+112
-21
lines changed

4 files changed

+112
-21
lines changed

jeecgboot-vue3/src/components/Form/src/componentMap.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,15 @@ componentMap.set('JInputSelect', JInputSelect);
179179
componentMap.set('JSelectDepartPost', JSelectDepartPost);
180180
componentMap.set('JSelectUserByDeptPost', JSelectUserByDeptPost);
181181

182-
182+
componentMap.set('OnlineSelectCascade', createAsyncComponent(() => {
183+
return import('@jeecg/online').then(mod => mod.OnlineSelectCascade);
184+
}));
185+
componentMap.set('LinkTableCard', createAsyncComponent(() => {
186+
return import('@jeecg/online').then(mod => mod.LinkTableCard);
187+
}));
188+
componentMap.set('LinkTableSelect', createAsyncComponent(() => {
189+
return import('@jeecg/online').then(mod => mod.LinkTableSelect);
190+
}));
183191

184192
export function add(compName: ComponentType, component: Component) {
185193
componentMap.set(compName, component);

jeecgboot-vue3/src/components/Form/src/hooks/useForm.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
66
import { isProdMode } from '/@/utils/env';
77
import { error } from '/@/utils/log';
88
import { getDynamicProps, getValueType, getValueTypeBySchema } from '/@/utils';
9-
import { add } from "/@/components/Form/src/componentMap";
10-
//集成online专用控件
11-
import { OnlineSelectCascade, LinkTableCard, LinkTableSelect } from '@jeecg/online';
12-
139
export declare type ValidateFields = (nameList?: NamePath[], options?: ValidateOptions) => Promise<Recordable>;
1410

1511
type Props = Partial<DynamicProps<FormProps>>;
@@ -18,11 +14,6 @@ export function useForm(props?: Props): UseFormReturnType {
1814
const formRef = ref<Nullable<FormActionType>>(null);
1915
const loadedRef = ref<Nullable<boolean>>(false);
2016

21-
//集成online专用控件
22-
add("OnlineSelectCascade", OnlineSelectCascade)
23-
add("LinkTableCard", LinkTableCard)
24-
add("LinkTableSelect", LinkTableSelect)
25-
2617
async function getForm() {
2718
const form = unref(formRef);
2819
if (!form) {

jeecgboot-vue3/src/router/helper/routeHelper.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { getTenantId, getToken } from "/@/utils/auth";
99
import { URL_HASH_TAB, _eval } from '/@/utils';
1010
//引入online lib路由
1111
import { packageViews } from '/@/utils/monorepo/dynamicRouter';
12+
import { loadPackageComponent } from '/@/utils/monorepo/registerPackages';
1213
import {useI18n} from "/@/hooks/web/useI18n";
1314

1415
export type LayoutMapKey = 'LAYOUT';
@@ -120,6 +121,12 @@ function dynamicImport(dynamicViewsModules: Record<string, () => Promise<Recorda
120121
);
121122
return;
122123
}
124+
// online/aiflow 本地未找到,尝试从懒加载包中按需加载
125+
if (component.startsWith('/super/online') || component.startsWith('/super/aiflow')) {
126+
return () => {
127+
return loadPackageComponent(component).then((factory) => (factory ? factory() : Promise.reject(`组件 ${component} 未找到`)));
128+
};
129+
}
123130
}
124131

125132
// Turn background objects into routing objects

jeecgboot-vue3/src/utils/monorepo/registerPackages.ts

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,109 @@
11
import type { App } from 'vue';
22
import { warn } from '/@/utils/log';
33
import { registerDynamicRouter } from '/@/utils/monorepo/dynamicRouter';
4-
// 引入模块
5-
import PACKAGE_JEECG_ONLINE from '@jeecg/online';
6-
import PACKAGE_JEECG_AIFLOW from '@jeecg/aiflow';
4+
import { add } from '/@/components/Form/src/componentMap';
75

8-
export function registerPackages(app: App) {
9-
use(app, PACKAGE_JEECG_ONLINE);
10-
use(app, PACKAGE_JEECG_AIFLOW);
11-
}
6+
// 懒加载模块配置(按需加载,访问相关路由时才加载对应包)
7+
const lazyPackages = [
8+
{ name: '@jeecg/online', importer: () => import('@jeecg/online') },
9+
{ name: '@jeecg/aiflow', importer: () => import('@jeecg/aiflow') },
10+
];
11+
12+
let appInstance: App | null = null;
1213

1314
// noinspection JSUnusedGlobalSymbols
1415
const installOptions = {
1516
baseImport,
1617
};
1718

18-
/** 注册模块 */
19-
function use(app: App, pkg) {
20-
app.use(pkg, installOptions);
21-
registerDynamicRouter(pkg.getViews);
19+
export function registerPackages(app: App) {
20+
// 仅保存 app 实例,不立即加载模块
21+
appInstance = app;
22+
}
23+
24+
/** 已加载的包缓存 */
25+
const loadedPackages = new Map<string, any>();
26+
/** 正在加载的包 Promise 缓存(防止重复加载) */
27+
const loadingPromises = new Map<string, Promise<any>>();
28+
29+
/**
30+
* 按需加载包并注册
31+
*/
32+
async function ensurePackageLoaded(pkgConfig: typeof lazyPackages[number]) {
33+
const { name, importer } = pkgConfig;
34+
if (loadedPackages.has(name)) {
35+
return loadedPackages.get(name);
36+
}
37+
if (!loadingPromises.has(name)) {
38+
const promise = importer().then((pkg) => {
39+
const mod = pkg.default || pkg;
40+
if (appInstance) {
41+
appInstance.use(mod, installOptions);
42+
registerDynamicRouter(mod.getViews);
43+
}
44+
loadedPackages.set(name, mod);
45+
loadingPromises.delete(name);
46+
return mod;
47+
});
48+
loadingPromises.set(name, promise);
49+
}
50+
return loadingPromises.get(name);
51+
}
52+
53+
/**
54+
* 根据 component 路径关键字匹配优先加载的包
55+
*/
56+
function getMatchedPackage(component: string): typeof lazyPackages[number] | null {
57+
const lc = component.toLowerCase();
58+
for (const pkgConfig of lazyPackages) {
59+
// 从包名中提取关键字,如 @jeecg/online -> online, @jeecg/aiflow -> aiflow
60+
const keyword = pkgConfig.name.split('/').pop()!;
61+
if (lc.includes(keyword)) {
62+
return pkgConfig;
63+
}
64+
}
65+
return null;
66+
}
67+
68+
/**
69+
* 从指定包中查找组件
70+
*/
71+
async function findComponentInPackage(pkgConfig: typeof lazyPackages[number], component: string): Promise<(() => Promise<Recordable>) | null> {
72+
try {
73+
const mod = await ensurePackageLoaded(pkgConfig);
74+
const views = mod.getViews();
75+
for (const key of Object.keys(views)) {
76+
const k = key.replace('./src/views', '');
77+
const startFlag = component.startsWith('/');
78+
const endFlag = component.endsWith('.vue') || component.endsWith('.tsx');
79+
const startIndex = startFlag ? 0 : 1;
80+
const lastIndex = endFlag ? k.length : k.lastIndexOf('.');
81+
if (k.substring(startIndex, lastIndex) === component) {
82+
return views[key];
83+
}
84+
}
85+
} catch (e) {
86+
// 包不存在或加载失败,跳过
87+
}
88+
return null;
89+
}
90+
91+
/**
92+
* 按需加载包组件:当路由匹配不到本地组件时调用
93+
* 根据 component 路径中的关键字优先匹配对应包,避免无意义的遍历
94+
*/
95+
export async function loadPackageComponent(component: string): Promise<(() => Promise<Recordable>) | null> {
96+
// 优先根据关键字精准匹配包
97+
const matched = getMatchedPackage(component);
98+
if (matched) {
99+
return findComponentInPackage(matched, component);
100+
}
101+
// 未匹配到关键字,依次尝试所有包
102+
for (const pkgConfig of lazyPackages) {
103+
const result = await findComponentInPackage(pkgConfig, component);
104+
if (result) return result;
105+
}
106+
return null;
22107
}
23108

24109
// 模块里可使用的import

0 commit comments

Comments
 (0)