@vlian/framework 1.2.37 → 1.2.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics.umd.js +1 -1
- package/dist/core/Test.cjs +2 -2
- package/dist/core/Test.cjs.map +1 -1
- package/dist/core/Test.js +1 -1
- package/dist/core/Test.js.map +1 -1
- package/dist/core/config/ConfigLoader.cjs +7 -7
- package/dist/core/config/ConfigLoader.cjs.map +1 -1
- package/dist/core/config/ConfigLoader.js +1 -1
- package/dist/core/config/ConfigLoader.js.map +1 -1
- package/dist/core/error/ErrorBoundary.cjs +6 -6
- package/dist/core/error/ErrorBoundary.cjs.map +1 -1
- package/dist/core/error/ErrorBoundary.d.ts +1 -1
- package/dist/core/error/ErrorBoundary.js +2 -2
- package/dist/core/error/ErrorBoundary.js.map +1 -1
- package/dist/core/error/ErrorHandler.cjs +19 -19
- package/dist/core/error/ErrorHandler.cjs.map +1 -1
- package/dist/core/error/ErrorHandler.d.ts +1 -1
- package/dist/core/error/ErrorHandler.js +2 -2
- package/dist/core/error/ErrorHandler.js.map +1 -1
- package/dist/core/event/AppEventBus.cjs +5 -5
- package/dist/core/event/AppEventBus.cjs.map +1 -1
- package/dist/core/event/AppEventBus.js +1 -1
- package/dist/core/event/AppEventBus.js.map +1 -1
- package/dist/core/initialization/InitializationErrorThrower.cjs.map +1 -1
- package/dist/core/initialization/InitializationErrorThrower.js.map +1 -1
- package/dist/core/initialization/initialization.cjs +3 -3
- package/dist/core/initialization/initialization.cjs.map +1 -1
- package/dist/core/initialization/initialization.d.ts +1 -1
- package/dist/core/initialization/initialization.js +1 -1
- package/dist/core/initialization/initialization.js.map +1 -1
- package/dist/core/initialization/initializationErrorState.cjs +2 -2
- package/dist/core/initialization/initializationErrorState.cjs.map +1 -1
- package/dist/core/initialization/initializationErrorState.d.ts +1 -1
- package/dist/core/initialization/initializationErrorState.js +1 -1
- package/dist/core/initialization/initializationErrorState.js.map +1 -1
- package/dist/core/kernel/defaultAdapters.cjs +14 -13
- package/dist/core/kernel/defaultAdapters.cjs.map +1 -1
- package/dist/core/kernel/defaultAdapters.js +2 -1
- package/dist/core/kernel/defaultAdapters.js.map +1 -1
- package/dist/core/kernel/types.d.ts +1 -1
- package/dist/core/kernel/types.js.map +1 -1
- package/dist/core/router/RouterManager.cjs +9 -9
- package/dist/core/router/RouterManager.cjs.map +1 -1
- package/dist/core/router/RouterManager.js +1 -1
- package/dist/core/router/RouterManager.js.map +1 -1
- package/dist/core/router/adapter/AdapterManager.cjs +10 -10
- package/dist/core/router/adapter/AdapterManager.cjs.map +1 -1
- package/dist/core/router/adapter/AdapterManager.js +1 -1
- package/dist/core/router/adapter/AdapterManager.js.map +1 -1
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.cjs +4 -4
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.cjs.map +1 -1
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.js +1 -1
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.js.map +1 -1
- package/dist/core/router/dynamic/DynamicRouteManager.cjs +8 -8
- package/dist/core/router/dynamic/DynamicRouteManager.cjs.map +1 -1
- package/dist/core/router/dynamic/DynamicRouteManager.js +1 -1
- package/dist/core/router/dynamic/DynamicRouteManager.js.map +1 -1
- package/dist/core/router/errors/RouterError.cjs +4 -4
- package/dist/core/router/errors/RouterError.cjs.map +1 -1
- package/dist/core/router/errors/RouterError.d.ts +1 -1
- package/dist/core/router/errors/RouterError.js +1 -1
- package/dist/core/router/errors/RouterError.js.map +1 -1
- package/dist/core/router/lifecycle/RouterLifecycleManager.cjs +8 -8
- package/dist/core/router/lifecycle/RouterLifecycleManager.cjs.map +1 -1
- package/dist/core/router/lifecycle/RouterLifecycleManager.js +1 -1
- package/dist/core/router/lifecycle/RouterLifecycleManager.js.map +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.cjs +11 -11
- package/dist/core/router/middleware/RouterMiddlewareManager.cjs.map +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.js +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.js.map +1 -1
- package/dist/core/router/middleware/auth.cjs +4 -4
- package/dist/core/router/middleware/auth.cjs.map +1 -1
- package/dist/core/router/middleware/auth.js +1 -1
- package/dist/core/router/middleware/auth.js.map +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.cjs +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.cjs.map +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.js +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.js.map +1 -1
- package/dist/core/router/navigation/RouterNavigation.cjs +7 -7
- package/dist/core/router/navigation/RouterNavigation.cjs.map +1 -1
- package/dist/core/router/navigation/RouterNavigation.js +1 -1
- package/dist/core/router/navigation/RouterNavigation.js.map +1 -1
- package/dist/core/router/performance/RouteCache.cjs +7 -7
- package/dist/core/router/performance/RouteCache.cjs.map +1 -1
- package/dist/core/router/performance/RouteCache.js +1 -1
- package/dist/core/router/performance/RouteCache.js.map +1 -1
- package/dist/core/router/performance/RoutePreloader.cjs +6 -6
- package/dist/core/router/performance/RoutePreloader.cjs.map +1 -1
- package/dist/core/router/performance/RoutePreloader.js +1 -1
- package/dist/core/router/performance/RoutePreloader.js.map +1 -1
- package/dist/core/router/plugin/RouterPluginManager.cjs +8 -8
- package/dist/core/router/plugin/RouterPluginManager.cjs.map +1 -1
- package/dist/core/router/plugin/RouterPluginManager.js +1 -1
- package/dist/core/router/plugin/RouterPluginManager.js.map +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.cjs +2 -2
- package/dist/core/router/utils/adapters/react-router/transform.cjs.map +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.js +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.js.map +1 -1
- package/dist/core/router/utils/transform.cjs +13 -12
- package/dist/core/router/utils/transform.cjs.map +1 -1
- package/dist/core/router/utils/transform.js +2 -1
- package/dist/core/router/utils/transform.js.map +1 -1
- package/dist/core/router/validation/RouterConfigValidator.cjs +2 -2
- package/dist/core/router/validation/RouterConfigValidator.cjs.map +1 -1
- package/dist/core/router/validation/RouterConfigValidator.js +1 -1
- package/dist/core/router/validation/RouterConfigValidator.js.map +1 -1
- package/dist/core/router/version/RouteVersionManager.cjs +6 -6
- package/dist/core/router/version/RouteVersionManager.cjs.map +1 -1
- package/dist/core/router/version/RouteVersionManager.js +1 -1
- package/dist/core/router/version/RouteVersionManager.js.map +1 -1
- package/dist/core/splash/SplashScreen.cjs +4 -4
- package/dist/core/splash/SplashScreen.cjs.map +1 -1
- package/dist/core/splash/SplashScreen.js +1 -1
- package/dist/core/splash/SplashScreen.js.map +1 -1
- package/dist/core/startup/initializeServices.cjs +14 -14
- package/dist/core/startup/initializeServices.cjs.map +1 -1
- package/dist/core/startup/initializeServices.d.ts +1 -1
- package/dist/core/startup/initializeServices.js +2 -2
- package/dist/core/startup/initializeServices.js.map +1 -1
- package/dist/core/startup/renderApp.cjs +2 -2
- package/dist/core/startup/renderApp.cjs.map +1 -1
- package/dist/core/startup/renderApp.js +1 -1
- package/dist/core/startup/renderApp.js.map +1 -1
- package/dist/core/startup/startApp.cjs +22 -22
- package/dist/core/startup/startApp.cjs.map +1 -1
- package/dist/core/startup/startApp.js +2 -2
- package/dist/core/startup/startApp.js.map +1 -1
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js.map +1 -1
- package/dist/index.umd.js +1394 -1401
- package/dist/index.umd.js.map +1 -1
- package/dist/kernel/constants.cjs +2 -2
- package/dist/kernel/constants.cjs.map +1 -1
- package/dist/kernel/constants.js +1 -1
- package/dist/kernel/constants.js.map +1 -1
- package/dist/kernel/manager/loggerManager.cjs +10 -10
- package/dist/kernel/manager/loggerManager.cjs.map +1 -1
- package/dist/kernel/manager/loggerManager.d.ts +1 -1
- package/dist/kernel/manager/loggerManager.js +1 -1
- package/dist/kernel/manager/loggerManager.js.map +1 -1
- package/dist/kernel/types.d.ts +1 -1
- package/dist/kernel/types.js.map +1 -1
- package/dist/library/storage/encryption.cjs +12 -13
- package/dist/library/storage/encryption.cjs.map +1 -1
- package/dist/library/storage/encryption.js +1 -2
- package/dist/library/storage/encryption.js.map +1 -1
- package/dist/state.umd.js +1 -1
- package/dist/utils/errors.cjs +71 -15
- package/dist/utils/errors.cjs.map +1 -1
- package/dist/utils/errors.d.ts +30 -1
- package/dist/utils/errors.js +16 -1
- package/dist/utils/errors.js.map +1 -1
- package/package.json +1 -1
|
@@ -22,7 +22,7 @@ _export(exports, {
|
|
|
22
22
|
return getRoutePreloader;
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
|
-
const
|
|
25
|
+
const _logger = require("@vlian/logger");
|
|
26
26
|
function _define_property(obj, key, value) {
|
|
27
27
|
if (key in obj) {
|
|
28
28
|
Object.defineProperty(obj, key, {
|
|
@@ -172,10 +172,10 @@ let RoutePreloader = class RoutePreloader {
|
|
|
172
172
|
]);
|
|
173
173
|
task.status = 'loaded';
|
|
174
174
|
const duration = Date.now() - (task.startTime || 0);
|
|
175
|
-
|
|
175
|
+
_logger.logger.debug(`路由组件预加载成功: ${task.routeName} (${duration}ms)`);
|
|
176
176
|
} catch (error) {
|
|
177
177
|
task.status = 'failed';
|
|
178
|
-
|
|
178
|
+
_logger.logger.warn(`路由组件预加载失败: ${task.routeName}`, error);
|
|
179
179
|
} finally{
|
|
180
180
|
if (timeoutId) {
|
|
181
181
|
clearTimeout(timeoutId);
|
|
@@ -208,7 +208,7 @@ let RoutePreloader = class RoutePreloader {
|
|
|
208
208
|
if (tasks.length === 0) {
|
|
209
209
|
return;
|
|
210
210
|
}
|
|
211
|
-
|
|
211
|
+
_logger.logger.debug(`开始预加载 ${tasks.length} 个路由组件`);
|
|
212
212
|
// 根据策略决定预加载哪些任务
|
|
213
213
|
let tasksToPreload = [];
|
|
214
214
|
switch(this.config.strategy){
|
|
@@ -231,7 +231,7 @@ let RoutePreloader = class RoutePreloader {
|
|
|
231
231
|
const batch = tasksToPreload.slice(i, i + concurrency);
|
|
232
232
|
await Promise.all(batch.map((task)=>this.preloadTask(task)));
|
|
233
233
|
}
|
|
234
|
-
|
|
234
|
+
_logger.logger.debug('路由组件预加载完成');
|
|
235
235
|
}
|
|
236
236
|
/**
|
|
237
237
|
* 停止预加载
|
|
@@ -251,7 +251,7 @@ let RoutePreloader = class RoutePreloader {
|
|
|
251
251
|
*/ clear() {
|
|
252
252
|
this.tasks.clear();
|
|
253
253
|
this.stopPreload();
|
|
254
|
-
|
|
254
|
+
_logger.logger.debug('路由预加载任务已清空');
|
|
255
255
|
}
|
|
256
256
|
/**
|
|
257
257
|
* 获取预加载统计信息
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/router/performance/RoutePreloader.ts"],"sourcesContent":["/**\n * 路由预加载管理器\n * 提供路由组件的预加载功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteConfig } from '../types';\nimport type { ComponentImport } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 预加载策略\n */\nexport enum PreloadStrategy {\n /**\n * 不预加载\n */\n NONE = 'none',\n\n /**\n * 预加载当前路由的下一级路由\n */\n NEXT_LEVEL = 'next-level',\n\n /**\n * 预加载所有路由\n */\n ALL = 'all',\n\n /**\n * 预加载可见路由(根据路由配置的优先级)\n */\n VISIBLE = 'visible',\n}\n\n/**\n * 预加载配置\n */\nexport interface PreloadConfig {\n /**\n * 预加载策略\n * @default PreloadStrategy.NEXT_LEVEL\n */\n strategy?: PreloadStrategy;\n\n /**\n * 预加载延迟(毫秒)\n * @default 1000\n */\n delay?: number;\n\n /**\n * 预加载优先级阈值(只预加载优先级小于等于此值的路由)\n * @default 10\n */\n priorityThreshold?: number;\n\n /**\n * 预加载超时时间(毫秒)\n * @default 5000\n */\n timeout?: number;\n}\n\n/**\n * 预加载任务\n */\ninterface PreloadTask {\n /**\n * 组件导入函数\n */\n importFn: ComponentImport;\n /**\n * 路由名称\n */\n routeName: string;\n /**\n * 优先级\n */\n priority: number;\n /**\n * 状态\n */\n status: 'pending' | 'loading' | 'loaded' | 'failed';\n /**\n * 开始时间\n */\n startTime?: number;\n}\n\n/**\n * 路由预加载管理器\n */\nexport class RoutePreloader {\n private tasks: Map<string, PreloadTask> = new Map();\n private config: Required<PreloadConfig>;\n private preloadTimer: ReturnType<typeof setTimeout> | null = null;\n private idleHandle: number | null = null;\n\n constructor(config: PreloadConfig = {}) {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n /**\n * 更新预加载配置\n */\n updateConfig(config: PreloadConfig = {}): void {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n private shouldRegister(priority: number): boolean {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return false;\n }\n\n if (\n this.config.strategy === PreloadStrategy.VISIBLE &&\n priority > this.config.priorityThreshold\n ) {\n return false;\n }\n\n return true;\n }\n\n private registerTask(\n key: string,\n importFn: ComponentImport,\n routeName: string,\n priority: number\n ): void {\n if (!this.shouldRegister(priority)) {\n return;\n }\n\n this.tasks.set(key, {\n importFn,\n routeName,\n priority,\n status: 'pending',\n });\n }\n\n /**\n * 注册路由用于预加载\n */\n registerRoute(route: RouteConfig): void {\n if (!route.page && !route.layout) {\n return;\n }\n\n const priority = route.handle?.order ?? 999;\n\n // 注册页面组件\n if (route.page && typeof route.page === 'function') {\n this.registerTask(`${route.name}_page`, route.page, route.name, priority);\n }\n\n // 注册布局组件\n if (route.layout && typeof route.layout === 'function') {\n this.registerTask(`${route.name}_layout`, route.layout, route.name, priority);\n }\n\n // 递归注册子路由\n if (route.children) {\n route.children.forEach((child) => this.registerRoute(child));\n }\n }\n\n /**\n * 注册多个路由\n */\n registerRoutes(\n routes: RouteConfig[],\n resolvers?: Pick<TransformRoutesResult, 'pages' | 'layouts' | 'errors' | 'loadings'>\n ): void {\n const priorityByPath = new Map<string, number>();\n const nameByPath = new Map<string, string>();\n\n const collectPriority = (route: RouteConfig): void => {\n const priority = route.handle?.order ?? 999;\n const routeName = route.name;\n\n const record = (value: unknown) => {\n if (typeof value !== 'string') {\n return;\n }\n if (!priorityByPath.has(value) || (priorityByPath.get(value) ?? 999) > priority) {\n priorityByPath.set(value, priority);\n nameByPath.set(value, routeName);\n }\n };\n\n record(route.page);\n record(route.layout);\n record(route.error ?? route.errors);\n record(route.loading);\n\n route.children?.forEach(collectPriority);\n };\n\n routes.forEach(collectPriority);\n routes.forEach((route) => this.registerRoute(route));\n\n if (!resolvers) {\n return;\n }\n\n const registerResolverMap = (\n map: Map<string, ComponentImport>,\n type: 'page' | 'layout' | 'error' | 'loading'\n ) => {\n for (const [path, importFn] of map.entries()) {\n const routeName = nameByPath.get(path) ?? path;\n const priority = priorityByPath.get(path) ?? 999;\n this.registerTask(`${routeName}_${type}_${path}`, importFn, routeName, priority);\n }\n };\n\n registerResolverMap(resolvers.pages, 'page');\n registerResolverMap(resolvers.layouts, 'layout');\n registerResolverMap(resolvers.errors, 'error');\n registerResolverMap(resolvers.loadings, 'loading');\n }\n\n /**\n * 预加载指定路由\n */\n async preloadRoute(routeName: string): Promise<void> {\n const tasks = Array.from(this.tasks.values()).filter(\n (task) => task.routeName === routeName && task.status === 'pending'\n );\n\n if (tasks.length === 0) {\n return;\n }\n\n await Promise.all(tasks.map((task) => this.preloadTask(task)));\n }\n\n /**\n * 预加载任务\n */\n private async preloadTask(task: PreloadTask): Promise<void> {\n if (task.status !== 'pending') {\n return;\n }\n\n task.status = 'loading';\n task.startTime = Date.now();\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n try {\n // 设置超时\n const timeoutPromise = new Promise((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error('预加载超时')), this.config.timeout);\n });\n\n // 执行预加载\n await Promise.race([task.importFn(), timeoutPromise]);\n\n task.status = 'loaded';\n const duration = Date.now() - (task.startTime || 0);\n logger.debug(`路由组件预加载成功: ${task.routeName} (${duration}ms)`);\n } catch (error) {\n task.status = 'failed';\n logger.warn(`路由组件预加载失败: ${task.routeName}`, error);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * 开始预加载(根据策略)\n */\n startPreload(): void {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return;\n }\n\n this.stopPreload();\n\n // 延迟预加载,避免影响初始渲染\n this.preloadTimer = setTimeout(() => {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n requestIdleCallback?: (callback: () => void) => number;\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (browserWindow?.requestIdleCallback) {\n this.idleHandle = browserWindow.requestIdleCallback(() => {\n this.executePreload();\n });\n return;\n }\n\n this.executePreload();\n }, this.config.delay);\n }\n\n /**\n * 执行预加载\n */\n private async executePreload(): Promise<void> {\n const tasks = Array.from(this.tasks.values())\n .filter((task) => task.status === 'pending')\n .sort((a, b) => a.priority - b.priority);\n\n if (tasks.length === 0) {\n return;\n }\n\n logger.debug(`开始预加载 ${tasks.length} 个路由组件`);\n\n // 根据策略决定预加载哪些任务\n let tasksToPreload: PreloadTask[] = [];\n\n switch (this.config.strategy) {\n case PreloadStrategy.ALL:\n tasksToPreload = tasks;\n break;\n case PreloadStrategy.NEXT_LEVEL:\n // 只预加载优先级最低的(最可能访问的)\n tasksToPreload = tasks.slice(0, Math.min(5, tasks.length));\n break;\n case PreloadStrategy.VISIBLE:\n tasksToPreload = tasks.filter(\n (task) => task.priority <= this.config.priorityThreshold\n );\n break;\n default:\n return;\n }\n\n // 并行预加载(限制并发数)\n const concurrency = 3;\n for (let i = 0; i < tasksToPreload.length; i += concurrency) {\n const batch = tasksToPreload.slice(i, i + concurrency);\n await Promise.all(batch.map((task) => this.preloadTask(task)));\n }\n\n logger.debug('路由组件预加载完成');\n }\n\n /**\n * 停止预加载\n */\n stopPreload(): void {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (this.preloadTimer) {\n clearTimeout(this.preloadTimer);\n this.preloadTimer = null;\n }\n if (this.idleHandle !== null && browserWindow?.cancelIdleCallback) {\n browserWindow.cancelIdleCallback(this.idleHandle);\n this.idleHandle = null;\n }\n }\n\n /**\n * 清空所有任务\n */\n clear(): void {\n this.tasks.clear();\n this.stopPreload();\n logger.debug('路由预加载任务已清空');\n }\n\n /**\n * 获取预加载统计信息\n */\n getStats(): {\n total: number;\n pending: number;\n loading: number;\n loaded: number;\n failed: number;\n } {\n const stats = {\n total: this.tasks.size,\n pending: 0,\n loading: 0,\n loaded: 0,\n failed: 0,\n };\n\n for (const task of this.tasks.values()) {\n stats[task.status]++;\n }\n\n return stats;\n }\n}\n\n/**\n * 获取路由预加载管理器单例\n */\nlet routePreloaderInstance: RoutePreloader | null = null;\n\nexport function getRoutePreloader(config?: PreloadConfig): RoutePreloader {\n if (!routePreloaderInstance) {\n routePreloaderInstance = new RoutePreloader(config);\n }\n return routePreloaderInstance;\n}\n"],"names":["PreloadStrategy","RoutePreloader","getRoutePreloader","updateConfig","config","strategy","delay","priorityThreshold","timeout","shouldRegister","priority","registerTask","key","importFn","routeName","tasks","set","status","registerRoute","route","page","layout","handle","order","name","children","forEach","child","registerRoutes","routes","resolvers","priorityByPath","Map","nameByPath","collectPriority","record","value","has","get","error","errors","loading","registerResolverMap","map","type","path","entries","pages","layouts","loadings","preloadRoute","Array","from","values","filter","task","length","Promise","all","preloadTask","startTime","Date","now","timeoutId","timeoutPromise","_","reject","setTimeout","Error","race","duration","logger","debug","warn","clearTimeout","startPreload","stopPreload","preloadTimer","browserWindow","window","undefined","requestIdleCallback","idleHandle","executePreload","sort","a","b","tasksToPreload","slice","Math","min","concurrency","i","batch","cancelIdleCallback","clear","getStats","stats","total","size","pending","loaded","failed","routePreloaderInstance"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/router/performance/RoutePreloader.ts"],"sourcesContent":["/**\n * 路由预加载管理器\n * 提供路由组件的预加载功能\n */\n\nimport { logger } from '@vlian/logger';\nimport type { RouteConfig } from '../types';\nimport type { ComponentImport } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 预加载策略\n */\nexport enum PreloadStrategy {\n /**\n * 不预加载\n */\n NONE = 'none',\n\n /**\n * 预加载当前路由的下一级路由\n */\n NEXT_LEVEL = 'next-level',\n\n /**\n * 预加载所有路由\n */\n ALL = 'all',\n\n /**\n * 预加载可见路由(根据路由配置的优先级)\n */\n VISIBLE = 'visible',\n}\n\n/**\n * 预加载配置\n */\nexport interface PreloadConfig {\n /**\n * 预加载策略\n * @default PreloadStrategy.NEXT_LEVEL\n */\n strategy?: PreloadStrategy;\n\n /**\n * 预加载延迟(毫秒)\n * @default 1000\n */\n delay?: number;\n\n /**\n * 预加载优先级阈值(只预加载优先级小于等于此值的路由)\n * @default 10\n */\n priorityThreshold?: number;\n\n /**\n * 预加载超时时间(毫秒)\n * @default 5000\n */\n timeout?: number;\n}\n\n/**\n * 预加载任务\n */\ninterface PreloadTask {\n /**\n * 组件导入函数\n */\n importFn: ComponentImport;\n /**\n * 路由名称\n */\n routeName: string;\n /**\n * 优先级\n */\n priority: number;\n /**\n * 状态\n */\n status: 'pending' | 'loading' | 'loaded' | 'failed';\n /**\n * 开始时间\n */\n startTime?: number;\n}\n\n/**\n * 路由预加载管理器\n */\nexport class RoutePreloader {\n private tasks: Map<string, PreloadTask> = new Map();\n private config: Required<PreloadConfig>;\n private preloadTimer: ReturnType<typeof setTimeout> | null = null;\n private idleHandle: number | null = null;\n\n constructor(config: PreloadConfig = {}) {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n /**\n * 更新预加载配置\n */\n updateConfig(config: PreloadConfig = {}): void {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n private shouldRegister(priority: number): boolean {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return false;\n }\n\n if (\n this.config.strategy === PreloadStrategy.VISIBLE &&\n priority > this.config.priorityThreshold\n ) {\n return false;\n }\n\n return true;\n }\n\n private registerTask(\n key: string,\n importFn: ComponentImport,\n routeName: string,\n priority: number\n ): void {\n if (!this.shouldRegister(priority)) {\n return;\n }\n\n this.tasks.set(key, {\n importFn,\n routeName,\n priority,\n status: 'pending',\n });\n }\n\n /**\n * 注册路由用于预加载\n */\n registerRoute(route: RouteConfig): void {\n if (!route.page && !route.layout) {\n return;\n }\n\n const priority = route.handle?.order ?? 999;\n\n // 注册页面组件\n if (route.page && typeof route.page === 'function') {\n this.registerTask(`${route.name}_page`, route.page, route.name, priority);\n }\n\n // 注册布局组件\n if (route.layout && typeof route.layout === 'function') {\n this.registerTask(`${route.name}_layout`, route.layout, route.name, priority);\n }\n\n // 递归注册子路由\n if (route.children) {\n route.children.forEach((child) => this.registerRoute(child));\n }\n }\n\n /**\n * 注册多个路由\n */\n registerRoutes(\n routes: RouteConfig[],\n resolvers?: Pick<TransformRoutesResult, 'pages' | 'layouts' | 'errors' | 'loadings'>\n ): void {\n const priorityByPath = new Map<string, number>();\n const nameByPath = new Map<string, string>();\n\n const collectPriority = (route: RouteConfig): void => {\n const priority = route.handle?.order ?? 999;\n const routeName = route.name;\n\n const record = (value: unknown) => {\n if (typeof value !== 'string') {\n return;\n }\n if (!priorityByPath.has(value) || (priorityByPath.get(value) ?? 999) > priority) {\n priorityByPath.set(value, priority);\n nameByPath.set(value, routeName);\n }\n };\n\n record(route.page);\n record(route.layout);\n record(route.error ?? route.errors);\n record(route.loading);\n\n route.children?.forEach(collectPriority);\n };\n\n routes.forEach(collectPriority);\n routes.forEach((route) => this.registerRoute(route));\n\n if (!resolvers) {\n return;\n }\n\n const registerResolverMap = (\n map: Map<string, ComponentImport>,\n type: 'page' | 'layout' | 'error' | 'loading'\n ) => {\n for (const [path, importFn] of map.entries()) {\n const routeName = nameByPath.get(path) ?? path;\n const priority = priorityByPath.get(path) ?? 999;\n this.registerTask(`${routeName}_${type}_${path}`, importFn, routeName, priority);\n }\n };\n\n registerResolverMap(resolvers.pages, 'page');\n registerResolverMap(resolvers.layouts, 'layout');\n registerResolverMap(resolvers.errors, 'error');\n registerResolverMap(resolvers.loadings, 'loading');\n }\n\n /**\n * 预加载指定路由\n */\n async preloadRoute(routeName: string): Promise<void> {\n const tasks = Array.from(this.tasks.values()).filter(\n (task) => task.routeName === routeName && task.status === 'pending'\n );\n\n if (tasks.length === 0) {\n return;\n }\n\n await Promise.all(tasks.map((task) => this.preloadTask(task)));\n }\n\n /**\n * 预加载任务\n */\n private async preloadTask(task: PreloadTask): Promise<void> {\n if (task.status !== 'pending') {\n return;\n }\n\n task.status = 'loading';\n task.startTime = Date.now();\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n try {\n // 设置超时\n const timeoutPromise = new Promise((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error('预加载超时')), this.config.timeout);\n });\n\n // 执行预加载\n await Promise.race([task.importFn(), timeoutPromise]);\n\n task.status = 'loaded';\n const duration = Date.now() - (task.startTime || 0);\n logger.debug(`路由组件预加载成功: ${task.routeName} (${duration}ms)`);\n } catch (error) {\n task.status = 'failed';\n logger.warn(`路由组件预加载失败: ${task.routeName}`, error);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * 开始预加载(根据策略)\n */\n startPreload(): void {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return;\n }\n\n this.stopPreload();\n\n // 延迟预加载,避免影响初始渲染\n this.preloadTimer = setTimeout(() => {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n requestIdleCallback?: (callback: () => void) => number;\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (browserWindow?.requestIdleCallback) {\n this.idleHandle = browserWindow.requestIdleCallback(() => {\n this.executePreload();\n });\n return;\n }\n\n this.executePreload();\n }, this.config.delay);\n }\n\n /**\n * 执行预加载\n */\n private async executePreload(): Promise<void> {\n const tasks = Array.from(this.tasks.values())\n .filter((task) => task.status === 'pending')\n .sort((a, b) => a.priority - b.priority);\n\n if (tasks.length === 0) {\n return;\n }\n\n logger.debug(`开始预加载 ${tasks.length} 个路由组件`);\n\n // 根据策略决定预加载哪些任务\n let tasksToPreload: PreloadTask[] = [];\n\n switch (this.config.strategy) {\n case PreloadStrategy.ALL:\n tasksToPreload = tasks;\n break;\n case PreloadStrategy.NEXT_LEVEL:\n // 只预加载优先级最低的(最可能访问的)\n tasksToPreload = tasks.slice(0, Math.min(5, tasks.length));\n break;\n case PreloadStrategy.VISIBLE:\n tasksToPreload = tasks.filter(\n (task) => task.priority <= this.config.priorityThreshold\n );\n break;\n default:\n return;\n }\n\n // 并行预加载(限制并发数)\n const concurrency = 3;\n for (let i = 0; i < tasksToPreload.length; i += concurrency) {\n const batch = tasksToPreload.slice(i, i + concurrency);\n await Promise.all(batch.map((task) => this.preloadTask(task)));\n }\n\n logger.debug('路由组件预加载完成');\n }\n\n /**\n * 停止预加载\n */\n stopPreload(): void {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (this.preloadTimer) {\n clearTimeout(this.preloadTimer);\n this.preloadTimer = null;\n }\n if (this.idleHandle !== null && browserWindow?.cancelIdleCallback) {\n browserWindow.cancelIdleCallback(this.idleHandle);\n this.idleHandle = null;\n }\n }\n\n /**\n * 清空所有任务\n */\n clear(): void {\n this.tasks.clear();\n this.stopPreload();\n logger.debug('路由预加载任务已清空');\n }\n\n /**\n * 获取预加载统计信息\n */\n getStats(): {\n total: number;\n pending: number;\n loading: number;\n loaded: number;\n failed: number;\n } {\n const stats = {\n total: this.tasks.size,\n pending: 0,\n loading: 0,\n loaded: 0,\n failed: 0,\n };\n\n for (const task of this.tasks.values()) {\n stats[task.status]++;\n }\n\n return stats;\n }\n}\n\n/**\n * 获取路由预加载管理器单例\n */\nlet routePreloaderInstance: RoutePreloader | null = null;\n\nexport function getRoutePreloader(config?: PreloadConfig): RoutePreloader {\n if (!routePreloaderInstance) {\n routePreloaderInstance = new RoutePreloader(config);\n }\n return routePreloaderInstance;\n}\n"],"names":["PreloadStrategy","RoutePreloader","getRoutePreloader","updateConfig","config","strategy","delay","priorityThreshold","timeout","shouldRegister","priority","registerTask","key","importFn","routeName","tasks","set","status","registerRoute","route","page","layout","handle","order","name","children","forEach","child","registerRoutes","routes","resolvers","priorityByPath","Map","nameByPath","collectPriority","record","value","has","get","error","errors","loading","registerResolverMap","map","type","path","entries","pages","layouts","loadings","preloadRoute","Array","from","values","filter","task","length","Promise","all","preloadTask","startTime","Date","now","timeoutId","timeoutPromise","_","reject","setTimeout","Error","race","duration","logger","debug","warn","clearTimeout","startPreload","stopPreload","preloadTimer","browserWindow","window","undefined","requestIdleCallback","idleHandle","executePreload","sort","a","b","tasksToPreload","slice","Math","min","concurrency","i","batch","cancelIdleCallback","clear","getStats","stats","total","size","pending","loaded","failed","routePreloaderInstance"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ function _define_property(obj, key, value) {
|
|
|
14
14
|
/**
|
|
15
15
|
* 路由预加载管理器
|
|
16
16
|
* 提供路由组件的预加载功能
|
|
17
|
-
*/ import { logger } from "
|
|
17
|
+
*/ import { logger } from "@vlian/logger";
|
|
18
18
|
/**
|
|
19
19
|
* 预加载策略
|
|
20
20
|
*/ export var PreloadStrategy = /*#__PURE__*/ function(PreloadStrategy) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/router/performance/RoutePreloader.ts"],"sourcesContent":["/**\n * 路由预加载管理器\n * 提供路由组件的预加载功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteConfig } from '../types';\nimport type { ComponentImport } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 预加载策略\n */\nexport enum PreloadStrategy {\n /**\n * 不预加载\n */\n NONE = 'none',\n\n /**\n * 预加载当前路由的下一级路由\n */\n NEXT_LEVEL = 'next-level',\n\n /**\n * 预加载所有路由\n */\n ALL = 'all',\n\n /**\n * 预加载可见路由(根据路由配置的优先级)\n */\n VISIBLE = 'visible',\n}\n\n/**\n * 预加载配置\n */\nexport interface PreloadConfig {\n /**\n * 预加载策略\n * @default PreloadStrategy.NEXT_LEVEL\n */\n strategy?: PreloadStrategy;\n\n /**\n * 预加载延迟(毫秒)\n * @default 1000\n */\n delay?: number;\n\n /**\n * 预加载优先级阈值(只预加载优先级小于等于此值的路由)\n * @default 10\n */\n priorityThreshold?: number;\n\n /**\n * 预加载超时时间(毫秒)\n * @default 5000\n */\n timeout?: number;\n}\n\n/**\n * 预加载任务\n */\ninterface PreloadTask {\n /**\n * 组件导入函数\n */\n importFn: ComponentImport;\n /**\n * 路由名称\n */\n routeName: string;\n /**\n * 优先级\n */\n priority: number;\n /**\n * 状态\n */\n status: 'pending' | 'loading' | 'loaded' | 'failed';\n /**\n * 开始时间\n */\n startTime?: number;\n}\n\n/**\n * 路由预加载管理器\n */\nexport class RoutePreloader {\n private tasks: Map<string, PreloadTask> = new Map();\n private config: Required<PreloadConfig>;\n private preloadTimer: ReturnType<typeof setTimeout> | null = null;\n private idleHandle: number | null = null;\n\n constructor(config: PreloadConfig = {}) {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n /**\n * 更新预加载配置\n */\n updateConfig(config: PreloadConfig = {}): void {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n private shouldRegister(priority: number): boolean {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return false;\n }\n\n if (\n this.config.strategy === PreloadStrategy.VISIBLE &&\n priority > this.config.priorityThreshold\n ) {\n return false;\n }\n\n return true;\n }\n\n private registerTask(\n key: string,\n importFn: ComponentImport,\n routeName: string,\n priority: number\n ): void {\n if (!this.shouldRegister(priority)) {\n return;\n }\n\n this.tasks.set(key, {\n importFn,\n routeName,\n priority,\n status: 'pending',\n });\n }\n\n /**\n * 注册路由用于预加载\n */\n registerRoute(route: RouteConfig): void {\n if (!route.page && !route.layout) {\n return;\n }\n\n const priority = route.handle?.order ?? 999;\n\n // 注册页面组件\n if (route.page && typeof route.page === 'function') {\n this.registerTask(`${route.name}_page`, route.page, route.name, priority);\n }\n\n // 注册布局组件\n if (route.layout && typeof route.layout === 'function') {\n this.registerTask(`${route.name}_layout`, route.layout, route.name, priority);\n }\n\n // 递归注册子路由\n if (route.children) {\n route.children.forEach((child) => this.registerRoute(child));\n }\n }\n\n /**\n * 注册多个路由\n */\n registerRoutes(\n routes: RouteConfig[],\n resolvers?: Pick<TransformRoutesResult, 'pages' | 'layouts' | 'errors' | 'loadings'>\n ): void {\n const priorityByPath = new Map<string, number>();\n const nameByPath = new Map<string, string>();\n\n const collectPriority = (route: RouteConfig): void => {\n const priority = route.handle?.order ?? 999;\n const routeName = route.name;\n\n const record = (value: unknown) => {\n if (typeof value !== 'string') {\n return;\n }\n if (!priorityByPath.has(value) || (priorityByPath.get(value) ?? 999) > priority) {\n priorityByPath.set(value, priority);\n nameByPath.set(value, routeName);\n }\n };\n\n record(route.page);\n record(route.layout);\n record(route.error ?? route.errors);\n record(route.loading);\n\n route.children?.forEach(collectPriority);\n };\n\n routes.forEach(collectPriority);\n routes.forEach((route) => this.registerRoute(route));\n\n if (!resolvers) {\n return;\n }\n\n const registerResolverMap = (\n map: Map<string, ComponentImport>,\n type: 'page' | 'layout' | 'error' | 'loading'\n ) => {\n for (const [path, importFn] of map.entries()) {\n const routeName = nameByPath.get(path) ?? path;\n const priority = priorityByPath.get(path) ?? 999;\n this.registerTask(`${routeName}_${type}_${path}`, importFn, routeName, priority);\n }\n };\n\n registerResolverMap(resolvers.pages, 'page');\n registerResolverMap(resolvers.layouts, 'layout');\n registerResolverMap(resolvers.errors, 'error');\n registerResolverMap(resolvers.loadings, 'loading');\n }\n\n /**\n * 预加载指定路由\n */\n async preloadRoute(routeName: string): Promise<void> {\n const tasks = Array.from(this.tasks.values()).filter(\n (task) => task.routeName === routeName && task.status === 'pending'\n );\n\n if (tasks.length === 0) {\n return;\n }\n\n await Promise.all(tasks.map((task) => this.preloadTask(task)));\n }\n\n /**\n * 预加载任务\n */\n private async preloadTask(task: PreloadTask): Promise<void> {\n if (task.status !== 'pending') {\n return;\n }\n\n task.status = 'loading';\n task.startTime = Date.now();\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n try {\n // 设置超时\n const timeoutPromise = new Promise((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error('预加载超时')), this.config.timeout);\n });\n\n // 执行预加载\n await Promise.race([task.importFn(), timeoutPromise]);\n\n task.status = 'loaded';\n const duration = Date.now() - (task.startTime || 0);\n logger.debug(`路由组件预加载成功: ${task.routeName} (${duration}ms)`);\n } catch (error) {\n task.status = 'failed';\n logger.warn(`路由组件预加载失败: ${task.routeName}`, error);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * 开始预加载(根据策略)\n */\n startPreload(): void {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return;\n }\n\n this.stopPreload();\n\n // 延迟预加载,避免影响初始渲染\n this.preloadTimer = setTimeout(() => {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n requestIdleCallback?: (callback: () => void) => number;\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (browserWindow?.requestIdleCallback) {\n this.idleHandle = browserWindow.requestIdleCallback(() => {\n this.executePreload();\n });\n return;\n }\n\n this.executePreload();\n }, this.config.delay);\n }\n\n /**\n * 执行预加载\n */\n private async executePreload(): Promise<void> {\n const tasks = Array.from(this.tasks.values())\n .filter((task) => task.status === 'pending')\n .sort((a, b) => a.priority - b.priority);\n\n if (tasks.length === 0) {\n return;\n }\n\n logger.debug(`开始预加载 ${tasks.length} 个路由组件`);\n\n // 根据策略决定预加载哪些任务\n let tasksToPreload: PreloadTask[] = [];\n\n switch (this.config.strategy) {\n case PreloadStrategy.ALL:\n tasksToPreload = tasks;\n break;\n case PreloadStrategy.NEXT_LEVEL:\n // 只预加载优先级最低的(最可能访问的)\n tasksToPreload = tasks.slice(0, Math.min(5, tasks.length));\n break;\n case PreloadStrategy.VISIBLE:\n tasksToPreload = tasks.filter(\n (task) => task.priority <= this.config.priorityThreshold\n );\n break;\n default:\n return;\n }\n\n // 并行预加载(限制并发数)\n const concurrency = 3;\n for (let i = 0; i < tasksToPreload.length; i += concurrency) {\n const batch = tasksToPreload.slice(i, i + concurrency);\n await Promise.all(batch.map((task) => this.preloadTask(task)));\n }\n\n logger.debug('路由组件预加载完成');\n }\n\n /**\n * 停止预加载\n */\n stopPreload(): void {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (this.preloadTimer) {\n clearTimeout(this.preloadTimer);\n this.preloadTimer = null;\n }\n if (this.idleHandle !== null && browserWindow?.cancelIdleCallback) {\n browserWindow.cancelIdleCallback(this.idleHandle);\n this.idleHandle = null;\n }\n }\n\n /**\n * 清空所有任务\n */\n clear(): void {\n this.tasks.clear();\n this.stopPreload();\n logger.debug('路由预加载任务已清空');\n }\n\n /**\n * 获取预加载统计信息\n */\n getStats(): {\n total: number;\n pending: number;\n loading: number;\n loaded: number;\n failed: number;\n } {\n const stats = {\n total: this.tasks.size,\n pending: 0,\n loading: 0,\n loaded: 0,\n failed: 0,\n };\n\n for (const task of this.tasks.values()) {\n stats[task.status]++;\n }\n\n return stats;\n }\n}\n\n/**\n * 获取路由预加载管理器单例\n */\nlet routePreloaderInstance: RoutePreloader | null = null;\n\nexport function getRoutePreloader(config?: PreloadConfig): RoutePreloader {\n if (!routePreloaderInstance) {\n routePreloaderInstance = new RoutePreloader(config);\n }\n return routePreloaderInstance;\n}\n"],"names":["logger","PreloadStrategy","RoutePreloader","updateConfig","config","strategy","delay","priorityThreshold","timeout","shouldRegister","priority","registerTask","key","importFn","routeName","tasks","set","status","registerRoute","route","page","layout","handle","order","name","children","forEach","child","registerRoutes","routes","resolvers","priorityByPath","Map","nameByPath","collectPriority","record","value","has","get","error","errors","loading","registerResolverMap","map","type","path","entries","pages","layouts","loadings","preloadRoute","Array","from","values","filter","task","length","Promise","all","preloadTask","startTime","Date","now","timeoutId","timeoutPromise","_","reject","setTimeout","Error","race","duration","debug","warn","clearTimeout","startPreload","stopPreload","preloadTimer","browserWindow","window","undefined","requestIdleCallback","idleHandle","executePreload","sort","a","b","tasksToPreload","slice","Math","min","concurrency","i","batch","cancelIdleCallback","clear","getStats","stats","total","size","pending","loaded","failed","routePreloaderInstance","getRoutePreloader"],"mappings":";;;;;;;;;;;;;AAAA;;;CAGC,GAED,SAASA,MAAM,QAAQ,iBAAiB;AAKxC;;CAEC,GACD,OAAO,IAAA,AAAKC,yCAAAA;IACV;;GAEC;IAGD;;GAEC;IAGD;;GAEC;IAGD;;GAEC;WAlBSA;MAoBX;AAyDD;;CAEC,GACD,OAAO,MAAMC;IAeX;;GAEC,GACDC,aAAaC,SAAwB,CAAC,CAAC,EAAQ;QAC7C,IAAI,CAACA,MAAM,GAAG;YACZC,UAAUD,OAAOC,QAAQ;YACzBC,OAAOF,OAAOE,KAAK,IAAI;YACvBC,mBAAmBH,OAAOG,iBAAiB,IAAI;YAC/CC,SAASJ,OAAOI,OAAO,IAAI;QAC7B;IACF;IAEQC,eAAeC,QAAgB,EAAW;QAChD,IAAI,IAAI,CAACN,MAAM,CAACC,QAAQ,aAA2B;YACjD,OAAO;QACT;QAEA,IACE,IAAI,CAACD,MAAM,CAACC,QAAQ,kBACpBK,WAAW,IAAI,CAACN,MAAM,CAACG,iBAAiB,EACxC;YACA,OAAO;QACT;QAEA,OAAO;IACT;IAEQI,aACNC,GAAW,EACXC,QAAyB,EACzBC,SAAiB,EACjBJ,QAAgB,EACV;QACN,IAAI,CAAC,IAAI,CAACD,cAAc,CAACC,WAAW;YAClC;QACF;QAEA,IAAI,CAACK,KAAK,CAACC,GAAG,CAACJ,KAAK;YAClBC;YACAC;YACAJ;YACAO,QAAQ;QACV;IACF;IAEA;;GAEC,GACDC,cAAcC,KAAkB,EAAQ;QACtC,IAAI,CAACA,MAAMC,IAAI,IAAI,CAACD,MAAME,MAAM,EAAE;YAChC;QACF;QAEA,MAAMX,WAAWS,MAAMG,MAAM,EAAEC,SAAS;QAExC,SAAS;QACT,IAAIJ,MAAMC,IAAI,IAAI,OAAOD,MAAMC,IAAI,KAAK,YAAY;YAClD,IAAI,CAACT,YAAY,CAAC,GAAGQ,MAAMK,IAAI,CAAC,KAAK,CAAC,EAAEL,MAAMC,IAAI,EAAED,MAAMK,IAAI,EAAEd;QAClE;QAEA,SAAS;QACT,IAAIS,MAAME,MAAM,IAAI,OAAOF,MAAME,MAAM,KAAK,YAAY;YACtD,IAAI,CAACV,YAAY,CAAC,GAAGQ,MAAMK,IAAI,CAAC,OAAO,CAAC,EAAEL,MAAME,MAAM,EAAEF,MAAMK,IAAI,EAAEd;QACtE;QAEA,UAAU;QACV,IAAIS,MAAMM,QAAQ,EAAE;YAClBN,MAAMM,QAAQ,CAACC,OAAO,CAAC,CAACC,QAAU,IAAI,CAACT,aAAa,CAACS;QACvD;IACF;IAEA;;GAEC,GACDC,eACEC,MAAqB,EACrBC,SAAoF,EAC9E;QACN,MAAMC,iBAAiB,IAAIC;QAC3B,MAAMC,aAAa,IAAID;QAEvB,MAAME,kBAAkB,CAACf;YACvB,MAAMT,WAAWS,MAAMG,MAAM,EAAEC,SAAS;YACxC,MAAMT,YAAYK,MAAMK,IAAI;YAE5B,MAAMW,SAAS,CAACC;gBACd,IAAI,OAAOA,UAAU,UAAU;oBAC7B;gBACF;gBACA,IAAI,CAACL,eAAeM,GAAG,CAACD,UAAU,AAACL,CAAAA,eAAeO,GAAG,CAACF,UAAU,GAAE,IAAK1B,UAAU;oBAC/EqB,eAAef,GAAG,CAACoB,OAAO1B;oBAC1BuB,WAAWjB,GAAG,CAACoB,OAAOtB;gBACxB;YACF;YAEAqB,OAAOhB,MAAMC,IAAI;YACjBe,OAAOhB,MAAME,MAAM;YACnBc,OAAOhB,MAAMoB,KAAK,IAAIpB,MAAMqB,MAAM;YAClCL,OAAOhB,MAAMsB,OAAO;YAEpBtB,MAAMM,QAAQ,EAAEC,QAAQQ;QAC1B;QAEAL,OAAOH,OAAO,CAACQ;QACfL,OAAOH,OAAO,CAAC,CAACP,QAAU,IAAI,CAACD,aAAa,CAACC;QAE7C,IAAI,CAACW,WAAW;YACd;QACF;QAEA,MAAMY,sBAAsB,CAC1BC,KACAC;YAEA,KAAK,MAAM,CAACC,MAAMhC,SAAS,IAAI8B,IAAIG,OAAO,GAAI;gBAC5C,MAAMhC,YAAYmB,WAAWK,GAAG,CAACO,SAASA;gBAC1C,MAAMnC,WAAWqB,eAAeO,GAAG,CAACO,SAAS;gBAC7C,IAAI,CAAClC,YAAY,CAAC,GAAGG,UAAU,CAAC,EAAE8B,KAAK,CAAC,EAAEC,MAAM,EAAEhC,UAAUC,WAAWJ;YACzE;QACF;QAEAgC,oBAAoBZ,UAAUiB,KAAK,EAAE;QACrCL,oBAAoBZ,UAAUkB,OAAO,EAAE;QACvCN,oBAAoBZ,UAAUU,MAAM,EAAE;QACtCE,oBAAoBZ,UAAUmB,QAAQ,EAAE;IAC1C;IAEA;;GAEC,GACD,MAAMC,aAAapC,SAAiB,EAAiB;QACnD,MAAMC,QAAQoC,MAAMC,IAAI,CAAC,IAAI,CAACrC,KAAK,CAACsC,MAAM,IAAIC,MAAM,CAClD,CAACC,OAASA,KAAKzC,SAAS,KAAKA,aAAayC,KAAKtC,MAAM,KAAK;QAG5D,IAAIF,MAAMyC,MAAM,KAAK,GAAG;YACtB;QACF;QAEA,MAAMC,QAAQC,GAAG,CAAC3C,MAAM4B,GAAG,CAAC,CAACY,OAAS,IAAI,CAACI,WAAW,CAACJ;IACzD;IAEA;;GAEC,GACD,MAAcI,YAAYJ,IAAiB,EAAiB;QAC1D,IAAIA,KAAKtC,MAAM,KAAK,WAAW;YAC7B;QACF;QAEAsC,KAAKtC,MAAM,GAAG;QACdsC,KAAKK,SAAS,GAAGC,KAAKC,GAAG;QAEzB,IAAIC,YAAkD;QAEtD,IAAI;YACF,OAAO;YACP,MAAMC,iBAAiB,IAAIP,QAAQ,CAACQ,GAAGC;gBACrCH,YAAYI,WAAW,IAAMD,OAAO,IAAIE,MAAM,WAAW,IAAI,CAAChE,MAAM,CAACI,OAAO;YAC9E;YAEA,QAAQ;YACR,MAAMiD,QAAQY,IAAI,CAAC;gBAACd,KAAK1C,QAAQ;gBAAImD;aAAe;YAEpDT,KAAKtC,MAAM,GAAG;YACd,MAAMqD,WAAWT,KAAKC,GAAG,KAAMP,CAAAA,KAAKK,SAAS,IAAI,CAAA;YACjD5D,OAAOuE,KAAK,CAAC,CAAC,WAAW,EAAEhB,KAAKzC,SAAS,CAAC,EAAE,EAAEwD,SAAS,GAAG,CAAC;QAC7D,EAAE,OAAO/B,OAAO;YACdgB,KAAKtC,MAAM,GAAG;YACdjB,OAAOwE,IAAI,CAAC,CAAC,WAAW,EAAEjB,KAAKzC,SAAS,EAAE,EAAEyB;QAC9C,SAAU;YACR,IAAIwB,WAAW;gBACbU,aAAaV;YACf;QACF;IACF;IAEA;;GAEC,GACDW,eAAqB;QACnB,IAAI,IAAI,CAACtE,MAAM,CAACC,QAAQ,aAA2B;YACjD;QACF;QAEA,IAAI,CAACsE,WAAW;QAEhB,iBAAiB;QACjB,IAAI,CAACC,YAAY,GAAGT,WAAW;YAC7B,MAAMU,gBAAgB,OAAOC,WAAW,cAAeA,SAGlDC;YAEL,IAAIF,eAAeG,qBAAqB;gBACtC,IAAI,CAACC,UAAU,GAAGJ,cAAcG,mBAAmB,CAAC;oBAClD,IAAI,CAACE,cAAc;gBACrB;gBACA;YACF;YAEA,IAAI,CAACA,cAAc;QACrB,GAAG,IAAI,CAAC9E,MAAM,CAACE,KAAK;IACtB;IAEA;;GAEC,GACD,MAAc4E,iBAAgC;QAC5C,MAAMnE,QAAQoC,MAAMC,IAAI,CAAC,IAAI,CAACrC,KAAK,CAACsC,MAAM,IACvCC,MAAM,CAAC,CAACC,OAASA,KAAKtC,MAAM,KAAK,WACjCkE,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAE1E,QAAQ,GAAG2E,EAAE3E,QAAQ;QAEzC,IAAIK,MAAMyC,MAAM,KAAK,GAAG;YACtB;QACF;QAEAxD,OAAOuE,KAAK,CAAC,CAAC,MAAM,EAAExD,MAAMyC,MAAM,CAAC,MAAM,CAAC;QAE1C,gBAAgB;QAChB,IAAI8B,iBAAgC,EAAE;QAEtC,OAAQ,IAAI,CAAClF,MAAM,CAACC,QAAQ;YAC1B;gBACEiF,iBAAiBvE;gBACjB;YACF;gBACE,qBAAqB;gBACrBuE,iBAAiBvE,MAAMwE,KAAK,CAAC,GAAGC,KAAKC,GAAG,CAAC,GAAG1E,MAAMyC,MAAM;gBACxD;YACF;gBACE8B,iBAAiBvE,MAAMuC,MAAM,CAC3B,CAACC,OAASA,KAAK7C,QAAQ,IAAI,IAAI,CAACN,MAAM,CAACG,iBAAiB;gBAE1D;YACF;gBACE;QACJ;QAEA,eAAe;QACf,MAAMmF,cAAc;QACpB,IAAK,IAAIC,IAAI,GAAGA,IAAIL,eAAe9B,MAAM,EAAEmC,KAAKD,YAAa;YAC3D,MAAME,QAAQN,eAAeC,KAAK,CAACI,GAAGA,IAAID;YAC1C,MAAMjC,QAAQC,GAAG,CAACkC,MAAMjD,GAAG,CAAC,CAACY,OAAS,IAAI,CAACI,WAAW,CAACJ;QACzD;QAEAvD,OAAOuE,KAAK,CAAC;IACf;IAEA;;GAEC,GACDI,cAAoB;QAClB,MAAME,gBAAgB,OAAOC,WAAW,cAAeA,SAElDC;QAEL,IAAI,IAAI,CAACH,YAAY,EAAE;YACrBH,aAAa,IAAI,CAACG,YAAY;YAC9B,IAAI,CAACA,YAAY,GAAG;QACtB;QACA,IAAI,IAAI,CAACK,UAAU,KAAK,QAAQJ,eAAegB,oBAAoB;YACjEhB,cAAcgB,kBAAkB,CAAC,IAAI,CAACZ,UAAU;YAChD,IAAI,CAACA,UAAU,GAAG;QACpB;IACF;IAEA;;GAEC,GACDa,QAAc;QACZ,IAAI,CAAC/E,KAAK,CAAC+E,KAAK;QAChB,IAAI,CAACnB,WAAW;QAChB3E,OAAOuE,KAAK,CAAC;IACf;IAEA;;GAEC,GACDwB,WAME;QACA,MAAMC,QAAQ;YACZC,OAAO,IAAI,CAAClF,KAAK,CAACmF,IAAI;YACtBC,SAAS;YACT1D,SAAS;YACT2D,QAAQ;YACRC,QAAQ;QACV;QAEA,KAAK,MAAM9C,QAAQ,IAAI,CAACxC,KAAK,CAACsC,MAAM,GAAI;YACtC2C,KAAK,CAACzC,KAAKtC,MAAM,CAAC;QACpB;QAEA,OAAO+E;IACT;IApTA,YAAY5F,SAAwB,CAAC,CAAC,CAAE;QALxC,uBAAQW,SAAkC,IAAIiB;QAC9C,uBAAQ5B,UAAR,KAAA;QACA,uBAAQwE,gBAAqD;QAC7D,uBAAQK,cAA4B;QAGlC,IAAI,CAAC7E,MAAM,GAAG;YACZC,UAAUD,OAAOC,QAAQ;YACzBC,OAAOF,OAAOE,KAAK,IAAI;YACvBC,mBAAmBH,OAAOG,iBAAiB,IAAI;YAC/CC,SAASJ,OAAOI,OAAO,IAAI;QAC7B;IACF;AA8SF;AAEA;;CAEC,GACD,IAAI8F,yBAAgD;AAEpD,OAAO,SAASC,kBAAkBnG,MAAsB;IACtD,IAAI,CAACkG,wBAAwB;QAC3BA,yBAAyB,IAAIpG,eAAeE;IAC9C;IACA,OAAOkG;AACT"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/router/performance/RoutePreloader.ts"],"sourcesContent":["/**\n * 路由预加载管理器\n * 提供路由组件的预加载功能\n */\n\nimport { logger } from '@vlian/logger';\nimport type { RouteConfig } from '../types';\nimport type { ComponentImport } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 预加载策略\n */\nexport enum PreloadStrategy {\n /**\n * 不预加载\n */\n NONE = 'none',\n\n /**\n * 预加载当前路由的下一级路由\n */\n NEXT_LEVEL = 'next-level',\n\n /**\n * 预加载所有路由\n */\n ALL = 'all',\n\n /**\n * 预加载可见路由(根据路由配置的优先级)\n */\n VISIBLE = 'visible',\n}\n\n/**\n * 预加载配置\n */\nexport interface PreloadConfig {\n /**\n * 预加载策略\n * @default PreloadStrategy.NEXT_LEVEL\n */\n strategy?: PreloadStrategy;\n\n /**\n * 预加载延迟(毫秒)\n * @default 1000\n */\n delay?: number;\n\n /**\n * 预加载优先级阈值(只预加载优先级小于等于此值的路由)\n * @default 10\n */\n priorityThreshold?: number;\n\n /**\n * 预加载超时时间(毫秒)\n * @default 5000\n */\n timeout?: number;\n}\n\n/**\n * 预加载任务\n */\ninterface PreloadTask {\n /**\n * 组件导入函数\n */\n importFn: ComponentImport;\n /**\n * 路由名称\n */\n routeName: string;\n /**\n * 优先级\n */\n priority: number;\n /**\n * 状态\n */\n status: 'pending' | 'loading' | 'loaded' | 'failed';\n /**\n * 开始时间\n */\n startTime?: number;\n}\n\n/**\n * 路由预加载管理器\n */\nexport class RoutePreloader {\n private tasks: Map<string, PreloadTask> = new Map();\n private config: Required<PreloadConfig>;\n private preloadTimer: ReturnType<typeof setTimeout> | null = null;\n private idleHandle: number | null = null;\n\n constructor(config: PreloadConfig = {}) {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n /**\n * 更新预加载配置\n */\n updateConfig(config: PreloadConfig = {}): void {\n this.config = {\n strategy: config.strategy ?? PreloadStrategy.NONE,\n delay: config.delay ?? 1000,\n priorityThreshold: config.priorityThreshold ?? 10,\n timeout: config.timeout ?? 5000,\n };\n }\n\n private shouldRegister(priority: number): boolean {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return false;\n }\n\n if (\n this.config.strategy === PreloadStrategy.VISIBLE &&\n priority > this.config.priorityThreshold\n ) {\n return false;\n }\n\n return true;\n }\n\n private registerTask(\n key: string,\n importFn: ComponentImport,\n routeName: string,\n priority: number\n ): void {\n if (!this.shouldRegister(priority)) {\n return;\n }\n\n this.tasks.set(key, {\n importFn,\n routeName,\n priority,\n status: 'pending',\n });\n }\n\n /**\n * 注册路由用于预加载\n */\n registerRoute(route: RouteConfig): void {\n if (!route.page && !route.layout) {\n return;\n }\n\n const priority = route.handle?.order ?? 999;\n\n // 注册页面组件\n if (route.page && typeof route.page === 'function') {\n this.registerTask(`${route.name}_page`, route.page, route.name, priority);\n }\n\n // 注册布局组件\n if (route.layout && typeof route.layout === 'function') {\n this.registerTask(`${route.name}_layout`, route.layout, route.name, priority);\n }\n\n // 递归注册子路由\n if (route.children) {\n route.children.forEach((child) => this.registerRoute(child));\n }\n }\n\n /**\n * 注册多个路由\n */\n registerRoutes(\n routes: RouteConfig[],\n resolvers?: Pick<TransformRoutesResult, 'pages' | 'layouts' | 'errors' | 'loadings'>\n ): void {\n const priorityByPath = new Map<string, number>();\n const nameByPath = new Map<string, string>();\n\n const collectPriority = (route: RouteConfig): void => {\n const priority = route.handle?.order ?? 999;\n const routeName = route.name;\n\n const record = (value: unknown) => {\n if (typeof value !== 'string') {\n return;\n }\n if (!priorityByPath.has(value) || (priorityByPath.get(value) ?? 999) > priority) {\n priorityByPath.set(value, priority);\n nameByPath.set(value, routeName);\n }\n };\n\n record(route.page);\n record(route.layout);\n record(route.error ?? route.errors);\n record(route.loading);\n\n route.children?.forEach(collectPriority);\n };\n\n routes.forEach(collectPriority);\n routes.forEach((route) => this.registerRoute(route));\n\n if (!resolvers) {\n return;\n }\n\n const registerResolverMap = (\n map: Map<string, ComponentImport>,\n type: 'page' | 'layout' | 'error' | 'loading'\n ) => {\n for (const [path, importFn] of map.entries()) {\n const routeName = nameByPath.get(path) ?? path;\n const priority = priorityByPath.get(path) ?? 999;\n this.registerTask(`${routeName}_${type}_${path}`, importFn, routeName, priority);\n }\n };\n\n registerResolverMap(resolvers.pages, 'page');\n registerResolverMap(resolvers.layouts, 'layout');\n registerResolverMap(resolvers.errors, 'error');\n registerResolverMap(resolvers.loadings, 'loading');\n }\n\n /**\n * 预加载指定路由\n */\n async preloadRoute(routeName: string): Promise<void> {\n const tasks = Array.from(this.tasks.values()).filter(\n (task) => task.routeName === routeName && task.status === 'pending'\n );\n\n if (tasks.length === 0) {\n return;\n }\n\n await Promise.all(tasks.map((task) => this.preloadTask(task)));\n }\n\n /**\n * 预加载任务\n */\n private async preloadTask(task: PreloadTask): Promise<void> {\n if (task.status !== 'pending') {\n return;\n }\n\n task.status = 'loading';\n task.startTime = Date.now();\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n try {\n // 设置超时\n const timeoutPromise = new Promise((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error('预加载超时')), this.config.timeout);\n });\n\n // 执行预加载\n await Promise.race([task.importFn(), timeoutPromise]);\n\n task.status = 'loaded';\n const duration = Date.now() - (task.startTime || 0);\n logger.debug(`路由组件预加载成功: ${task.routeName} (${duration}ms)`);\n } catch (error) {\n task.status = 'failed';\n logger.warn(`路由组件预加载失败: ${task.routeName}`, error);\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * 开始预加载(根据策略)\n */\n startPreload(): void {\n if (this.config.strategy === PreloadStrategy.NONE) {\n return;\n }\n\n this.stopPreload();\n\n // 延迟预加载,避免影响初始渲染\n this.preloadTimer = setTimeout(() => {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n requestIdleCallback?: (callback: () => void) => number;\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (browserWindow?.requestIdleCallback) {\n this.idleHandle = browserWindow.requestIdleCallback(() => {\n this.executePreload();\n });\n return;\n }\n\n this.executePreload();\n }, this.config.delay);\n }\n\n /**\n * 执行预加载\n */\n private async executePreload(): Promise<void> {\n const tasks = Array.from(this.tasks.values())\n .filter((task) => task.status === 'pending')\n .sort((a, b) => a.priority - b.priority);\n\n if (tasks.length === 0) {\n return;\n }\n\n logger.debug(`开始预加载 ${tasks.length} 个路由组件`);\n\n // 根据策略决定预加载哪些任务\n let tasksToPreload: PreloadTask[] = [];\n\n switch (this.config.strategy) {\n case PreloadStrategy.ALL:\n tasksToPreload = tasks;\n break;\n case PreloadStrategy.NEXT_LEVEL:\n // 只预加载优先级最低的(最可能访问的)\n tasksToPreload = tasks.slice(0, Math.min(5, tasks.length));\n break;\n case PreloadStrategy.VISIBLE:\n tasksToPreload = tasks.filter(\n (task) => task.priority <= this.config.priorityThreshold\n );\n break;\n default:\n return;\n }\n\n // 并行预加载(限制并发数)\n const concurrency = 3;\n for (let i = 0; i < tasksToPreload.length; i += concurrency) {\n const batch = tasksToPreload.slice(i, i + concurrency);\n await Promise.all(batch.map((task) => this.preloadTask(task)));\n }\n\n logger.debug('路由组件预加载完成');\n }\n\n /**\n * 停止预加载\n */\n stopPreload(): void {\n const browserWindow = typeof window !== 'undefined' ? (window as Window & {\n cancelIdleCallback?: (id: number) => void;\n }) : undefined;\n\n if (this.preloadTimer) {\n clearTimeout(this.preloadTimer);\n this.preloadTimer = null;\n }\n if (this.idleHandle !== null && browserWindow?.cancelIdleCallback) {\n browserWindow.cancelIdleCallback(this.idleHandle);\n this.idleHandle = null;\n }\n }\n\n /**\n * 清空所有任务\n */\n clear(): void {\n this.tasks.clear();\n this.stopPreload();\n logger.debug('路由预加载任务已清空');\n }\n\n /**\n * 获取预加载统计信息\n */\n getStats(): {\n total: number;\n pending: number;\n loading: number;\n loaded: number;\n failed: number;\n } {\n const stats = {\n total: this.tasks.size,\n pending: 0,\n loading: 0,\n loaded: 0,\n failed: 0,\n };\n\n for (const task of this.tasks.values()) {\n stats[task.status]++;\n }\n\n return stats;\n }\n}\n\n/**\n * 获取路由预加载管理器单例\n */\nlet routePreloaderInstance: RoutePreloader | null = null;\n\nexport function getRoutePreloader(config?: PreloadConfig): RoutePreloader {\n if (!routePreloaderInstance) {\n routePreloaderInstance = new RoutePreloader(config);\n }\n return routePreloaderInstance;\n}\n"],"names":["logger","PreloadStrategy","RoutePreloader","updateConfig","config","strategy","delay","priorityThreshold","timeout","shouldRegister","priority","registerTask","key","importFn","routeName","tasks","set","status","registerRoute","route","page","layout","handle","order","name","children","forEach","child","registerRoutes","routes","resolvers","priorityByPath","Map","nameByPath","collectPriority","record","value","has","get","error","errors","loading","registerResolverMap","map","type","path","entries","pages","layouts","loadings","preloadRoute","Array","from","values","filter","task","length","Promise","all","preloadTask","startTime","Date","now","timeoutId","timeoutPromise","_","reject","setTimeout","Error","race","duration","debug","warn","clearTimeout","startPreload","stopPreload","preloadTimer","browserWindow","window","undefined","requestIdleCallback","idleHandle","executePreload","sort","a","b","tasksToPreload","slice","Math","min","concurrency","i","batch","cancelIdleCallback","clear","getStats","stats","total","size","pending","loaded","failed","routePreloaderInstance","getRoutePreloader"],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ _export(exports, {
|
|
|
19
19
|
return getRouterPluginManager;
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
|
-
const
|
|
22
|
+
const _logger = require("@vlian/logger");
|
|
23
23
|
const _types = require("./types");
|
|
24
24
|
function _define_property(obj, key, value) {
|
|
25
25
|
if (key in obj) {
|
|
@@ -69,7 +69,7 @@ let RouterPluginManager = class RouterPluginManager {
|
|
|
69
69
|
status: 'registered',
|
|
70
70
|
registeredAt: Date.now()
|
|
71
71
|
});
|
|
72
|
-
|
|
72
|
+
_logger.logger.debug(`路由插件已注册: ${plugin.name}`);
|
|
73
73
|
// 调用注册钩子
|
|
74
74
|
if (pluginWithDefaults.hooks?.onRegister) {
|
|
75
75
|
try {
|
|
@@ -81,7 +81,7 @@ let RouterPluginManager = class RouterPluginManager {
|
|
|
81
81
|
};
|
|
82
82
|
pluginWithDefaults.hooks.onRegister(context);
|
|
83
83
|
} catch (error) {
|
|
84
|
-
|
|
84
|
+
_logger.logger.error(`插件注册钩子执行失败: ${plugin.name}`, error);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
// 返回取消注册函数
|
|
@@ -155,11 +155,11 @@ let RouterPluginManager = class RouterPluginManager {
|
|
|
155
155
|
};
|
|
156
156
|
registration.plugin.hooks.onDestroy(context);
|
|
157
157
|
} catch (error) {
|
|
158
|
-
|
|
158
|
+
_logger.logger.error(`插件销毁钩子执行失败: ${name}`, error);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
this.plugins.delete(name);
|
|
162
|
-
|
|
162
|
+
_logger.logger.debug(`路由插件已取消注册: ${name}`);
|
|
163
163
|
}
|
|
164
164
|
/**
|
|
165
165
|
* 执行插件钩子
|
|
@@ -191,7 +191,7 @@ let RouterPluginManager = class RouterPluginManager {
|
|
|
191
191
|
try {
|
|
192
192
|
await hook(context);
|
|
193
193
|
} catch (error) {
|
|
194
|
-
|
|
194
|
+
_logger.logger.error(`插件钩子执行失败: ${registration.plugin.name}.${hookName}`, error);
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
}
|
|
@@ -233,12 +233,12 @@ let RouterPluginManager = class RouterPluginManager {
|
|
|
233
233
|
};
|
|
234
234
|
registration.plugin.hooks.onDestroy(context);
|
|
235
235
|
} catch (error) {
|
|
236
|
-
|
|
236
|
+
_logger.logger.error(`插件销毁钩子执行失败: ${name}`, error);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
this.plugins.clear();
|
|
241
|
-
|
|
241
|
+
_logger.logger.debug('所有路由插件已清空');
|
|
242
242
|
}
|
|
243
243
|
/**
|
|
244
244
|
* 获取插件数量
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/router/plugin/RouterPluginManager.ts"],"sourcesContent":["/**\n * 路由插件管理器\n * 负责插件的注册、执行和生命周期管理\n */\n\nimport { logger } from '../../../utils';\nimport type { RouterPlugin, PluginContext, PluginRegisterOptions } from './types';\nimport { PluginLifecycleStage } from './types';\n\n/**\n * 插件状态\n */\ntype PluginStatus = 'registered' | 'initialized' | 'destroyed';\n\n/**\n * 插件注册信息\n */\ninterface PluginRegistration {\n /**\n * 插件实例\n */\n plugin: RouterPlugin;\n\n /**\n * 插件状态\n */\n status: PluginStatus;\n\n /**\n * 注册时间\n */\n registeredAt: number;\n}\n\n/**\n * 路由插件管理器\n */\nexport class RouterPluginManager {\n private plugins: Map<string, PluginRegistration> = new Map();\n\n /**\n * 注册插件\n * \n * @param plugin - 插件实例\n * @param options - 注册选项\n * @returns 取消注册函数\n */\n register(plugin: RouterPlugin, options: PluginRegisterOptions = {}): () => void {\n // 验证插件\n if (!plugin.name) {\n throw new Error('插件必须提供名称');\n }\n\n // 检查是否已存在\n if (this.plugins.has(plugin.name) && !options.overwrite) {\n throw new Error(`插件 \"${plugin.name}\" 已存在`);\n }\n\n // 设置默认值\n const pluginWithDefaults: RouterPlugin = {\n priority: 100,\n enabled: true,\n ...plugin,\n };\n\n // 检查依赖\n if (pluginWithDefaults.dependencies) {\n const missingDeps = pluginWithDefaults.dependencies.filter(\n (dep) => !this.plugins.has(dep)\n );\n if (missingDeps.length > 0) {\n throw new Error(\n `插件 \"${plugin.name}\" 缺少依赖: ${missingDeps.join(', ')}`\n );\n }\n }\n\n // 注册插件\n this.plugins.set(plugin.name, {\n plugin: pluginWithDefaults,\n status: 'registered',\n registeredAt: Date.now(),\n });\n\n logger.debug(`路由插件已注册: ${plugin.name}`);\n\n // 调用注册钩子\n if (pluginWithDefaults.hooks?.onRegister) {\n try {\n const context: PluginContext = {\n config: {} as any, // 在注册阶段可能还没有配置\n meta: { stage: PluginLifecycleStage.REGISTER },\n };\n pluginWithDefaults.hooks.onRegister(context);\n } catch (error) {\n logger.error(`插件注册钩子执行失败: ${plugin.name}`, error);\n }\n }\n\n // 返回取消注册函数\n return () => {\n this.unregister(plugin.name);\n };\n }\n\n /**\n * 批量注册插件\n * \n * @param plugins - 插件数组\n * @param options - 注册选项\n */\n registerBatch(plugins: RouterPlugin[], options: PluginRegisterOptions = {}): void {\n // 按依赖关系排序\n const sortedPlugins = this.sortByDependencies(plugins);\n\n sortedPlugins.forEach((plugin) => {\n this.register(plugin, options);\n });\n }\n\n /**\n * 按依赖关系排序插件(拓扑排序)\n */\n private sortByDependencies(plugins: RouterPlugin[]): RouterPlugin[] {\n const sorted: RouterPlugin[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n const visit = (plugin: RouterPlugin): void => {\n if (visiting.has(plugin.name || '')) {\n throw new Error(`检测到循环依赖: ${plugin.name}`);\n }\n\n if (visited.has(plugin.name || '')) {\n return;\n }\n\n visiting.add(plugin.name || '');\n\n // 先访问依赖\n if (plugin.dependencies) {\n plugin.dependencies.forEach((depName) => {\n const dep = plugins.find((p) => p.name === depName);\n if (dep) {\n visit(dep);\n }\n });\n }\n\n visiting.delete(plugin.name || '');\n visited.add(plugin.name || '');\n sorted.push(plugin);\n };\n\n plugins.forEach((plugin) => {\n if (!visited.has(plugin.name || '')) {\n visit(plugin);\n }\n });\n\n return sorted;\n }\n\n /**\n * 取消注册插件\n * \n * @param name - 插件名称\n */\n unregister(name: string): void {\n const registration = this.plugins.get(name);\n if (!registration) {\n return;\n }\n\n // 调用销毁钩子\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n\n this.plugins.delete(name);\n logger.debug(`路由插件已取消注册: ${name}`);\n }\n\n /**\n * 执行插件钩子\n * \n * @param stage - 生命周期阶段\n * @param context - 插件上下文\n */\n async executeHooks(stage: PluginLifecycleStage, context: PluginContext): Promise<void> {\n // 获取启用的插件并按优先级排序\n const enabledPlugins = Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .sort((a, b) => (a.plugin.priority || 100) - (b.plugin.priority || 100));\n\n // 根据阶段选择钩子\n const hookMap: Partial<Record<PluginLifecycleStage, keyof NonNullable<RouterPlugin['hooks']>>> = {\n [PluginLifecycleStage.REGISTER]: 'onRegister',\n [PluginLifecycleStage.BEFORE_INIT]: 'onBeforeInit',\n [PluginLifecycleStage.AFTER_INIT]: 'onAfterInit',\n [PluginLifecycleStage.BEFORE_TRANSFORM]: 'onBeforeTransform',\n [PluginLifecycleStage.AFTER_TRANSFORM]: 'onAfterTransform',\n [PluginLifecycleStage.BEFORE_MATCH]: 'onBeforeMatch',\n [PluginLifecycleStage.AFTER_MATCH]: 'onAfterMatch',\n [PluginLifecycleStage.DESTROY]: 'onDestroy',\n };\n\n const hookName = hookMap[stage];\n if (!hookName) {\n return;\n }\n\n // 执行钩子\n for (const registration of enabledPlugins) {\n const hook = registration.plugin.hooks?.[hookName];\n if (hook) {\n try {\n await hook(context);\n } catch (error) {\n logger.error(`插件钩子执行失败: ${registration.plugin.name}.${hookName}`, error);\n }\n }\n }\n }\n\n /**\n * 获取插件\n * \n * @param name - 插件名称\n * @returns 插件实例,如果不存在返回 undefined\n */\n getPlugin(name: string): RouterPlugin | undefined {\n return this.plugins.get(name)?.plugin;\n }\n\n /**\n * 获取所有插件\n * \n * @returns 插件数组\n */\n getAllPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values()).map((reg) => reg.plugin);\n }\n\n /**\n * 获取启用的插件\n * \n * @returns 启用的插件数组\n */\n getEnabledPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .map((reg) => reg.plugin);\n }\n\n /**\n * 清空所有插件\n */\n clear(): void {\n // 调用所有插件的销毁钩子\n for (const [name, registration] of this.plugins.entries()) {\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n }\n\n this.plugins.clear();\n logger.debug('所有路由插件已清空');\n }\n\n /**\n * 获取插件数量\n * \n * @returns 插件数量\n */\n getCount(): number {\n return this.plugins.size;\n }\n}\n\n/**\n * 获取路由插件管理器单例\n */\nlet pluginManagerInstance: RouterPluginManager | null = null;\n\nexport function getRouterPluginManager(): RouterPluginManager {\n if (!pluginManagerInstance) {\n pluginManagerInstance = new RouterPluginManager();\n }\n return pluginManagerInstance;\n}\n"],"names":["RouterPluginManager","getRouterPluginManager","register","plugin","options","name","Error","plugins","has","overwrite","pluginWithDefaults","priority","enabled","dependencies","missingDeps","filter","dep","length","join","set","status","registeredAt","Date","now","logger","debug","hooks","onRegister","context","config","meta","stage","PluginLifecycleStage","REGISTER","error","unregister","registerBatch","sortedPlugins","sortByDependencies","forEach","sorted","visited","Set","visiting","visit","add","depName","find","p","delete","push","registration","get","onDestroy","DESTROY","executeHooks","enabledPlugins","Array","from","values","reg","sort","a","b","hookMap","BEFORE_INIT","AFTER_INIT","BEFORE_TRANSFORM","AFTER_TRANSFORM","BEFORE_MATCH","AFTER_MATCH","hookName","hook","getPlugin","getAllPlugins","map","getEnabledPlugins","clear","entries","getCount","size","Map","pluginManagerInstance"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/router/plugin/RouterPluginManager.ts"],"sourcesContent":["/**\n * 路由插件管理器\n * 负责插件的注册、执行和生命周期管理\n */\n\nimport { logger } from '@vlian/logger';\nimport type { RouterPlugin, PluginContext, PluginRegisterOptions } from './types';\nimport { PluginLifecycleStage } from './types';\n\n/**\n * 插件状态\n */\ntype PluginStatus = 'registered' | 'initialized' | 'destroyed';\n\n/**\n * 插件注册信息\n */\ninterface PluginRegistration {\n /**\n * 插件实例\n */\n plugin: RouterPlugin;\n\n /**\n * 插件状态\n */\n status: PluginStatus;\n\n /**\n * 注册时间\n */\n registeredAt: number;\n}\n\n/**\n * 路由插件管理器\n */\nexport class RouterPluginManager {\n private plugins: Map<string, PluginRegistration> = new Map();\n\n /**\n * 注册插件\n * \n * @param plugin - 插件实例\n * @param options - 注册选项\n * @returns 取消注册函数\n */\n register(plugin: RouterPlugin, options: PluginRegisterOptions = {}): () => void {\n // 验证插件\n if (!plugin.name) {\n throw new Error('插件必须提供名称');\n }\n\n // 检查是否已存在\n if (this.plugins.has(plugin.name) && !options.overwrite) {\n throw new Error(`插件 \"${plugin.name}\" 已存在`);\n }\n\n // 设置默认值\n const pluginWithDefaults: RouterPlugin = {\n priority: 100,\n enabled: true,\n ...plugin,\n };\n\n // 检查依赖\n if (pluginWithDefaults.dependencies) {\n const missingDeps = pluginWithDefaults.dependencies.filter(\n (dep) => !this.plugins.has(dep)\n );\n if (missingDeps.length > 0) {\n throw new Error(\n `插件 \"${plugin.name}\" 缺少依赖: ${missingDeps.join(', ')}`\n );\n }\n }\n\n // 注册插件\n this.plugins.set(plugin.name, {\n plugin: pluginWithDefaults,\n status: 'registered',\n registeredAt: Date.now(),\n });\n\n logger.debug(`路由插件已注册: ${plugin.name}`);\n\n // 调用注册钩子\n if (pluginWithDefaults.hooks?.onRegister) {\n try {\n const context: PluginContext = {\n config: {} as any, // 在注册阶段可能还没有配置\n meta: { stage: PluginLifecycleStage.REGISTER },\n };\n pluginWithDefaults.hooks.onRegister(context);\n } catch (error) {\n logger.error(`插件注册钩子执行失败: ${plugin.name}`, error);\n }\n }\n\n // 返回取消注册函数\n return () => {\n this.unregister(plugin.name);\n };\n }\n\n /**\n * 批量注册插件\n * \n * @param plugins - 插件数组\n * @param options - 注册选项\n */\n registerBatch(plugins: RouterPlugin[], options: PluginRegisterOptions = {}): void {\n // 按依赖关系排序\n const sortedPlugins = this.sortByDependencies(plugins);\n\n sortedPlugins.forEach((plugin) => {\n this.register(plugin, options);\n });\n }\n\n /**\n * 按依赖关系排序插件(拓扑排序)\n */\n private sortByDependencies(plugins: RouterPlugin[]): RouterPlugin[] {\n const sorted: RouterPlugin[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n const visit = (plugin: RouterPlugin): void => {\n if (visiting.has(plugin.name || '')) {\n throw new Error(`检测到循环依赖: ${plugin.name}`);\n }\n\n if (visited.has(plugin.name || '')) {\n return;\n }\n\n visiting.add(plugin.name || '');\n\n // 先访问依赖\n if (plugin.dependencies) {\n plugin.dependencies.forEach((depName) => {\n const dep = plugins.find((p) => p.name === depName);\n if (dep) {\n visit(dep);\n }\n });\n }\n\n visiting.delete(plugin.name || '');\n visited.add(plugin.name || '');\n sorted.push(plugin);\n };\n\n plugins.forEach((plugin) => {\n if (!visited.has(plugin.name || '')) {\n visit(plugin);\n }\n });\n\n return sorted;\n }\n\n /**\n * 取消注册插件\n * \n * @param name - 插件名称\n */\n unregister(name: string): void {\n const registration = this.plugins.get(name);\n if (!registration) {\n return;\n }\n\n // 调用销毁钩子\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n\n this.plugins.delete(name);\n logger.debug(`路由插件已取消注册: ${name}`);\n }\n\n /**\n * 执行插件钩子\n * \n * @param stage - 生命周期阶段\n * @param context - 插件上下文\n */\n async executeHooks(stage: PluginLifecycleStage, context: PluginContext): Promise<void> {\n // 获取启用的插件并按优先级排序\n const enabledPlugins = Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .sort((a, b) => (a.plugin.priority || 100) - (b.plugin.priority || 100));\n\n // 根据阶段选择钩子\n const hookMap: Partial<Record<PluginLifecycleStage, keyof NonNullable<RouterPlugin['hooks']>>> = {\n [PluginLifecycleStage.REGISTER]: 'onRegister',\n [PluginLifecycleStage.BEFORE_INIT]: 'onBeforeInit',\n [PluginLifecycleStage.AFTER_INIT]: 'onAfterInit',\n [PluginLifecycleStage.BEFORE_TRANSFORM]: 'onBeforeTransform',\n [PluginLifecycleStage.AFTER_TRANSFORM]: 'onAfterTransform',\n [PluginLifecycleStage.BEFORE_MATCH]: 'onBeforeMatch',\n [PluginLifecycleStage.AFTER_MATCH]: 'onAfterMatch',\n [PluginLifecycleStage.DESTROY]: 'onDestroy',\n };\n\n const hookName = hookMap[stage];\n if (!hookName) {\n return;\n }\n\n // 执行钩子\n for (const registration of enabledPlugins) {\n const hook = registration.plugin.hooks?.[hookName];\n if (hook) {\n try {\n await hook(context);\n } catch (error) {\n logger.error(`插件钩子执行失败: ${registration.plugin.name}.${hookName}`, error);\n }\n }\n }\n }\n\n /**\n * 获取插件\n * \n * @param name - 插件名称\n * @returns 插件实例,如果不存在返回 undefined\n */\n getPlugin(name: string): RouterPlugin | undefined {\n return this.plugins.get(name)?.plugin;\n }\n\n /**\n * 获取所有插件\n * \n * @returns 插件数组\n */\n getAllPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values()).map((reg) => reg.plugin);\n }\n\n /**\n * 获取启用的插件\n * \n * @returns 启用的插件数组\n */\n getEnabledPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .map((reg) => reg.plugin);\n }\n\n /**\n * 清空所有插件\n */\n clear(): void {\n // 调用所有插件的销毁钩子\n for (const [name, registration] of this.plugins.entries()) {\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n }\n\n this.plugins.clear();\n logger.debug('所有路由插件已清空');\n }\n\n /**\n * 获取插件数量\n * \n * @returns 插件数量\n */\n getCount(): number {\n return this.plugins.size;\n }\n}\n\n/**\n * 获取路由插件管理器单例\n */\nlet pluginManagerInstance: RouterPluginManager | null = null;\n\nexport function getRouterPluginManager(): RouterPluginManager {\n if (!pluginManagerInstance) {\n pluginManagerInstance = new RouterPluginManager();\n }\n return pluginManagerInstance;\n}\n"],"names":["RouterPluginManager","getRouterPluginManager","register","plugin","options","name","Error","plugins","has","overwrite","pluginWithDefaults","priority","enabled","dependencies","missingDeps","filter","dep","length","join","set","status","registeredAt","Date","now","logger","debug","hooks","onRegister","context","config","meta","stage","PluginLifecycleStage","REGISTER","error","unregister","registerBatch","sortedPlugins","sortByDependencies","forEach","sorted","visited","Set","visiting","visit","add","depName","find","p","delete","push","registration","get","onDestroy","DESTROY","executeHooks","enabledPlugins","Array","from","values","reg","sort","a","b","hookMap","BEFORE_INIT","AFTER_INIT","BEFORE_TRANSFORM","AFTER_TRANSFORM","BEFORE_MATCH","AFTER_MATCH","hookName","hook","getPlugin","getAllPlugins","map","getEnabledPlugins","clear","entries","getCount","size","Map","pluginManagerInstance"],"mappings":"AAAA;;;CAGC;;;;;;;;;;;QAkCYA;eAAAA;;QAwQGC;eAAAA;;;wBAxSO;uBAEc;;;;;;;;;;;;;;AA8B9B,IAAA,AAAMD,sBAAN,MAAMA;IAGX;;;;;;GAMC,GACDE,SAASC,MAAoB,EAAEC,UAAiC,CAAC,CAAC,EAAc;QAC9E,OAAO;QACP,IAAI,CAACD,OAAOE,IAAI,EAAE;YAChB,MAAM,IAAIC,MAAM;QAClB;QAEA,UAAU;QACV,IAAI,IAAI,CAACC,OAAO,CAACC,GAAG,CAACL,OAAOE,IAAI,KAAK,CAACD,QAAQK,SAAS,EAAE;YACvD,MAAM,IAAIH,MAAM,CAAC,IAAI,EAAEH,OAAOE,IAAI,CAAC,KAAK,CAAC;QAC3C;QAEA,QAAQ;QACR,MAAMK,qBAAmC;YACvCC,UAAU;YACVC,SAAS;YACT,GAAGT,MAAM;QACX;QAEA,OAAO;QACP,IAAIO,mBAAmBG,YAAY,EAAE;YACnC,MAAMC,cAAcJ,mBAAmBG,YAAY,CAACE,MAAM,CACxD,CAACC,MAAQ,CAAC,IAAI,CAACT,OAAO,CAACC,GAAG,CAACQ;YAE7B,IAAIF,YAAYG,MAAM,GAAG,GAAG;gBAC1B,MAAM,IAAIX,MACR,CAAC,IAAI,EAAEH,OAAOE,IAAI,CAAC,QAAQ,EAAES,YAAYI,IAAI,CAAC,OAAO;YAEzD;QACF;QAEA,OAAO;QACP,IAAI,CAACX,OAAO,CAACY,GAAG,CAAChB,OAAOE,IAAI,EAAE;YAC5BF,QAAQO;YACRU,QAAQ;YACRC,cAAcC,KAAKC,GAAG;QACxB;QAEAC,cAAM,CAACC,KAAK,CAAC,CAAC,SAAS,EAAEtB,OAAOE,IAAI,EAAE;QAEtC,SAAS;QACT,IAAIK,mBAAmBgB,KAAK,EAAEC,YAAY;YACxC,IAAI;gBACF,MAAMC,UAAyB;oBAC7BC,QAAQ,CAAC;oBACTC,MAAM;wBAAEC,OAAOC,2BAAoB,CAACC,QAAQ;oBAAC;gBAC/C;gBACAvB,mBAAmBgB,KAAK,CAACC,UAAU,CAACC;YACtC,EAAE,OAAOM,OAAO;gBACdV,cAAM,CAACU,KAAK,CAAC,CAAC,YAAY,EAAE/B,OAAOE,IAAI,EAAE,EAAE6B;YAC7C;QACF;QAEA,WAAW;QACX,OAAO;YACL,IAAI,CAACC,UAAU,CAAChC,OAAOE,IAAI;QAC7B;IACF;IAEA;;;;;GAKC,GACD+B,cAAc7B,OAAuB,EAAEH,UAAiC,CAAC,CAAC,EAAQ;QAChF,UAAU;QACV,MAAMiC,gBAAgB,IAAI,CAACC,kBAAkB,CAAC/B;QAE9C8B,cAAcE,OAAO,CAAC,CAACpC;YACrB,IAAI,CAACD,QAAQ,CAACC,QAAQC;QACxB;IACF;IAEA;;GAEC,GACD,AAAQkC,mBAAmB/B,OAAuB,EAAkB;QAClE,MAAMiC,SAAyB,EAAE;QACjC,MAAMC,UAAU,IAAIC;QACpB,MAAMC,WAAW,IAAID;QAErB,MAAME,QAAQ,CAACzC;YACb,IAAIwC,SAASnC,GAAG,CAACL,OAAOE,IAAI,IAAI,KAAK;gBACnC,MAAM,IAAIC,MAAM,CAAC,SAAS,EAAEH,OAAOE,IAAI,EAAE;YAC3C;YAEA,IAAIoC,QAAQjC,GAAG,CAACL,OAAOE,IAAI,IAAI,KAAK;gBAClC;YACF;YAEAsC,SAASE,GAAG,CAAC1C,OAAOE,IAAI,IAAI;YAE5B,QAAQ;YACR,IAAIF,OAAOU,YAAY,EAAE;gBACvBV,OAAOU,YAAY,CAAC0B,OAAO,CAAC,CAACO;oBAC3B,MAAM9B,MAAMT,QAAQwC,IAAI,CAAC,CAACC,IAAMA,EAAE3C,IAAI,KAAKyC;oBAC3C,IAAI9B,KAAK;wBACP4B,MAAM5B;oBACR;gBACF;YACF;YAEA2B,SAASM,MAAM,CAAC9C,OAAOE,IAAI,IAAI;YAC/BoC,QAAQI,GAAG,CAAC1C,OAAOE,IAAI,IAAI;YAC3BmC,OAAOU,IAAI,CAAC/C;QACd;QAEAI,QAAQgC,OAAO,CAAC,CAACpC;YACf,IAAI,CAACsC,QAAQjC,GAAG,CAACL,OAAOE,IAAI,IAAI,KAAK;gBACnCuC,MAAMzC;YACR;QACF;QAEA,OAAOqC;IACT;IAEA;;;;GAIC,GACDL,WAAW9B,IAAY,EAAQ;QAC7B,MAAM8C,eAAe,IAAI,CAAC5C,OAAO,CAAC6C,GAAG,CAAC/C;QACtC,IAAI,CAAC8C,cAAc;YACjB;QACF;QAEA,SAAS;QACT,IAAIA,aAAahD,MAAM,CAACuB,KAAK,EAAE2B,WAAW;YACxC,IAAI;gBACF,MAAMzB,UAAyB;oBAC7BC,QAAQ,CAAC;oBACTC,MAAM;wBAAEC,OAAOC,2BAAoB,CAACsB,OAAO;oBAAC;gBAC9C;gBACAH,aAAahD,MAAM,CAACuB,KAAK,CAAC2B,SAAS,CAACzB;YACtC,EAAE,OAAOM,OAAO;gBACdV,cAAM,CAACU,KAAK,CAAC,CAAC,YAAY,EAAE7B,MAAM,EAAE6B;YACtC;QACF;QAEA,IAAI,CAAC3B,OAAO,CAAC0C,MAAM,CAAC5C;QACpBmB,cAAM,CAACC,KAAK,CAAC,CAAC,WAAW,EAAEpB,MAAM;IACnC;IAEA;;;;;GAKC,GACD,MAAMkD,aAAaxB,KAA2B,EAAEH,OAAsB,EAAiB;QACrF,iBAAiB;QACjB,MAAM4B,iBAAiBC,MAAMC,IAAI,CAAC,IAAI,CAACnD,OAAO,CAACoD,MAAM,IAClD5C,MAAM,CAAC,CAAC6C,MAAQA,IAAIzD,MAAM,CAACS,OAAO,KAAK,OACvCiD,IAAI,CAAC,CAACC,GAAGC,IAAM,AAACD,CAAAA,EAAE3D,MAAM,CAACQ,QAAQ,IAAI,GAAE,IAAMoD,CAAAA,EAAE5D,MAAM,CAACQ,QAAQ,IAAI,GAAE;QAEvE,WAAW;QACX,MAAMqD,UAA2F;YAC/F,CAAChC,2BAAoB,CAACC,QAAQ,CAAC,EAAE;YACjC,CAACD,2BAAoB,CAACiC,WAAW,CAAC,EAAE;YACpC,CAACjC,2BAAoB,CAACkC,UAAU,CAAC,EAAE;YACnC,CAAClC,2BAAoB,CAACmC,gBAAgB,CAAC,EAAE;YACzC,CAACnC,2BAAoB,CAACoC,eAAe,CAAC,EAAE;YACxC,CAACpC,2BAAoB,CAACqC,YAAY,CAAC,EAAE;YACrC,CAACrC,2BAAoB,CAACsC,WAAW,CAAC,EAAE;YACpC,CAACtC,2BAAoB,CAACsB,OAAO,CAAC,EAAE;QAClC;QAEA,MAAMiB,WAAWP,OAAO,CAACjC,MAAM;QAC/B,IAAI,CAACwC,UAAU;YACb;QACF;QAEA,OAAO;QACP,KAAK,MAAMpB,gBAAgBK,eAAgB;YACzC,MAAMgB,OAAOrB,aAAahD,MAAM,CAACuB,KAAK,EAAE,CAAC6C,SAAS;YAClD,IAAIC,MAAM;gBACR,IAAI;oBACF,MAAMA,KAAK5C;gBACb,EAAE,OAAOM,OAAO;oBACdV,cAAM,CAACU,KAAK,CAAC,CAAC,UAAU,EAAEiB,aAAahD,MAAM,CAACE,IAAI,CAAC,CAAC,EAAEkE,UAAU,EAAErC;gBACpE;YACF;QACF;IACF;IAEA;;;;;GAKC,GACDuC,UAAUpE,IAAY,EAA4B;QAChD,OAAO,IAAI,CAACE,OAAO,CAAC6C,GAAG,CAAC/C,OAAOF;IACjC;IAEA;;;;GAIC,GACDuE,gBAAgC;QAC9B,OAAOjB,MAAMC,IAAI,CAAC,IAAI,CAACnD,OAAO,CAACoD,MAAM,IAAIgB,GAAG,CAAC,CAACf,MAAQA,IAAIzD,MAAM;IAClE;IAEA;;;;GAIC,GACDyE,oBAAoC;QAClC,OAAOnB,MAAMC,IAAI,CAAC,IAAI,CAACnD,OAAO,CAACoD,MAAM,IAClC5C,MAAM,CAAC,CAAC6C,MAAQA,IAAIzD,MAAM,CAACS,OAAO,KAAK,OACvC+D,GAAG,CAAC,CAACf,MAAQA,IAAIzD,MAAM;IAC5B;IAEA;;GAEC,GACD0E,QAAc;QACZ,cAAc;QACd,KAAK,MAAM,CAACxE,MAAM8C,aAAa,IAAI,IAAI,CAAC5C,OAAO,CAACuE,OAAO,GAAI;YACzD,IAAI3B,aAAahD,MAAM,CAACuB,KAAK,EAAE2B,WAAW;gBACxC,IAAI;oBACF,MAAMzB,UAAyB;wBAC7BC,QAAQ,CAAC;wBACTC,MAAM;4BAAEC,OAAOC,2BAAoB,CAACsB,OAAO;wBAAC;oBAC9C;oBACAH,aAAahD,MAAM,CAACuB,KAAK,CAAC2B,SAAS,CAACzB;gBACtC,EAAE,OAAOM,OAAO;oBACdV,cAAM,CAACU,KAAK,CAAC,CAAC,YAAY,EAAE7B,MAAM,EAAE6B;gBACtC;YACF;QACF;QAEA,IAAI,CAAC3B,OAAO,CAACsE,KAAK;QAClBrD,cAAM,CAACC,KAAK,CAAC;IACf;IAEA;;;;GAIC,GACDsD,WAAmB;QACjB,OAAO,IAAI,CAACxE,OAAO,CAACyE,IAAI;IAC1B;;QA/PA,uBAAQzE,WAA2C,IAAI0E;;AAgQzD;AAEA;;CAEC,GACD,IAAIC,wBAAoD;AAEjD,SAASjF;IACd,IAAI,CAACiF,uBAAuB;QAC1BA,wBAAwB,IAAIlF;IAC9B;IACA,OAAOkF;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/router/plugin/RouterPluginManager.ts"],"sourcesContent":["/**\n * 路由插件管理器\n * 负责插件的注册、执行和生命周期管理\n */\n\nimport { logger } from '../../../utils';\nimport type { RouterPlugin, PluginContext, PluginRegisterOptions } from './types';\nimport { PluginLifecycleStage } from './types';\n\n/**\n * 插件状态\n */\ntype PluginStatus = 'registered' | 'initialized' | 'destroyed';\n\n/**\n * 插件注册信息\n */\ninterface PluginRegistration {\n /**\n * 插件实例\n */\n plugin: RouterPlugin;\n\n /**\n * 插件状态\n */\n status: PluginStatus;\n\n /**\n * 注册时间\n */\n registeredAt: number;\n}\n\n/**\n * 路由插件管理器\n */\nexport class RouterPluginManager {\n private plugins: Map<string, PluginRegistration> = new Map();\n\n /**\n * 注册插件\n * \n * @param plugin - 插件实例\n * @param options - 注册选项\n * @returns 取消注册函数\n */\n register(plugin: RouterPlugin, options: PluginRegisterOptions = {}): () => void {\n // 验证插件\n if (!plugin.name) {\n throw new Error('插件必须提供名称');\n }\n\n // 检查是否已存在\n if (this.plugins.has(plugin.name) && !options.overwrite) {\n throw new Error(`插件 \"${plugin.name}\" 已存在`);\n }\n\n // 设置默认值\n const pluginWithDefaults: RouterPlugin = {\n priority: 100,\n enabled: true,\n ...plugin,\n };\n\n // 检查依赖\n if (pluginWithDefaults.dependencies) {\n const missingDeps = pluginWithDefaults.dependencies.filter(\n (dep) => !this.plugins.has(dep)\n );\n if (missingDeps.length > 0) {\n throw new Error(\n `插件 \"${plugin.name}\" 缺少依赖: ${missingDeps.join(', ')}`\n );\n }\n }\n\n // 注册插件\n this.plugins.set(plugin.name, {\n plugin: pluginWithDefaults,\n status: 'registered',\n registeredAt: Date.now(),\n });\n\n logger.debug(`路由插件已注册: ${plugin.name}`);\n\n // 调用注册钩子\n if (pluginWithDefaults.hooks?.onRegister) {\n try {\n const context: PluginContext = {\n config: {} as any, // 在注册阶段可能还没有配置\n meta: { stage: PluginLifecycleStage.REGISTER },\n };\n pluginWithDefaults.hooks.onRegister(context);\n } catch (error) {\n logger.error(`插件注册钩子执行失败: ${plugin.name}`, error);\n }\n }\n\n // 返回取消注册函数\n return () => {\n this.unregister(plugin.name);\n };\n }\n\n /**\n * 批量注册插件\n * \n * @param plugins - 插件数组\n * @param options - 注册选项\n */\n registerBatch(plugins: RouterPlugin[], options: PluginRegisterOptions = {}): void {\n // 按依赖关系排序\n const sortedPlugins = this.sortByDependencies(plugins);\n\n sortedPlugins.forEach((plugin) => {\n this.register(plugin, options);\n });\n }\n\n /**\n * 按依赖关系排序插件(拓扑排序)\n */\n private sortByDependencies(plugins: RouterPlugin[]): RouterPlugin[] {\n const sorted: RouterPlugin[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n const visit = (plugin: RouterPlugin): void => {\n if (visiting.has(plugin.name || '')) {\n throw new Error(`检测到循环依赖: ${plugin.name}`);\n }\n\n if (visited.has(plugin.name || '')) {\n return;\n }\n\n visiting.add(plugin.name || '');\n\n // 先访问依赖\n if (plugin.dependencies) {\n plugin.dependencies.forEach((depName) => {\n const dep = plugins.find((p) => p.name === depName);\n if (dep) {\n visit(dep);\n }\n });\n }\n\n visiting.delete(plugin.name || '');\n visited.add(plugin.name || '');\n sorted.push(plugin);\n };\n\n plugins.forEach((plugin) => {\n if (!visited.has(plugin.name || '')) {\n visit(plugin);\n }\n });\n\n return sorted;\n }\n\n /**\n * 取消注册插件\n * \n * @param name - 插件名称\n */\n unregister(name: string): void {\n const registration = this.plugins.get(name);\n if (!registration) {\n return;\n }\n\n // 调用销毁钩子\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n\n this.plugins.delete(name);\n logger.debug(`路由插件已取消注册: ${name}`);\n }\n\n /**\n * 执行插件钩子\n * \n * @param stage - 生命周期阶段\n * @param context - 插件上下文\n */\n async executeHooks(stage: PluginLifecycleStage, context: PluginContext): Promise<void> {\n // 获取启用的插件并按优先级排序\n const enabledPlugins = Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .sort((a, b) => (a.plugin.priority || 100) - (b.plugin.priority || 100));\n\n // 根据阶段选择钩子\n const hookMap: Partial<Record<PluginLifecycleStage, keyof NonNullable<RouterPlugin['hooks']>>> = {\n [PluginLifecycleStage.REGISTER]: 'onRegister',\n [PluginLifecycleStage.BEFORE_INIT]: 'onBeforeInit',\n [PluginLifecycleStage.AFTER_INIT]: 'onAfterInit',\n [PluginLifecycleStage.BEFORE_TRANSFORM]: 'onBeforeTransform',\n [PluginLifecycleStage.AFTER_TRANSFORM]: 'onAfterTransform',\n [PluginLifecycleStage.BEFORE_MATCH]: 'onBeforeMatch',\n [PluginLifecycleStage.AFTER_MATCH]: 'onAfterMatch',\n [PluginLifecycleStage.DESTROY]: 'onDestroy',\n };\n\n const hookName = hookMap[stage];\n if (!hookName) {\n return;\n }\n\n // 执行钩子\n for (const registration of enabledPlugins) {\n const hook = registration.plugin.hooks?.[hookName];\n if (hook) {\n try {\n await hook(context);\n } catch (error) {\n logger.error(`插件钩子执行失败: ${registration.plugin.name}.${hookName}`, error);\n }\n }\n }\n }\n\n /**\n * 获取插件\n * \n * @param name - 插件名称\n * @returns 插件实例,如果不存在返回 undefined\n */\n getPlugin(name: string): RouterPlugin | undefined {\n return this.plugins.get(name)?.plugin;\n }\n\n /**\n * 获取所有插件\n * \n * @returns 插件数组\n */\n getAllPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values()).map((reg) => reg.plugin);\n }\n\n /**\n * 获取启用的插件\n * \n * @returns 启用的插件数组\n */\n getEnabledPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .map((reg) => reg.plugin);\n }\n\n /**\n * 清空所有插件\n */\n clear(): void {\n // 调用所有插件的销毁钩子\n for (const [name, registration] of this.plugins.entries()) {\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n }\n\n this.plugins.clear();\n logger.debug('所有路由插件已清空');\n }\n\n /**\n * 获取插件数量\n * \n * @returns 插件数量\n */\n getCount(): number {\n return this.plugins.size;\n }\n}\n\n/**\n * 获取路由插件管理器单例\n */\nlet pluginManagerInstance: RouterPluginManager | null = null;\n\nexport function getRouterPluginManager(): RouterPluginManager {\n if (!pluginManagerInstance) {\n pluginManagerInstance = new RouterPluginManager();\n }\n return pluginManagerInstance;\n}\n"],"names":["logger","PluginLifecycleStage","RouterPluginManager","register","plugin","options","name","Error","plugins","has","overwrite","pluginWithDefaults","priority","enabled","dependencies","missingDeps","filter","dep","length","join","set","status","registeredAt","Date","now","debug","hooks","onRegister","context","config","meta","stage","REGISTER","error","unregister","registerBatch","sortedPlugins","sortByDependencies","forEach","sorted","visited","Set","visiting","visit","add","depName","find","p","delete","push","registration","get","onDestroy","DESTROY","executeHooks","enabledPlugins","Array","from","values","reg","sort","a","b","hookMap","BEFORE_INIT","AFTER_INIT","BEFORE_TRANSFORM","AFTER_TRANSFORM","BEFORE_MATCH","AFTER_MATCH","hookName","hook","getPlugin","getAllPlugins","map","getEnabledPlugins","clear","entries","getCount","size","Map","pluginManagerInstance","getRouterPluginManager"],"mappings":";;;;;;;;;;;;;AAAA;;;CAGC,GAED,SAASA,MAAM,QAAQ,iBAAiB;AAExC,SAASC,oBAAoB,QAAQ,UAAU;AA2B/C;;CAEC,GACD,OAAO,MAAMC;IAGX;;;;;;GAMC,GACDC,SAASC,MAAoB,EAAEC,UAAiC,CAAC,CAAC,EAAc;QAC9E,OAAO;QACP,IAAI,CAACD,OAAOE,IAAI,EAAE;YAChB,MAAM,IAAIC,MAAM;QAClB;QAEA,UAAU;QACV,IAAI,IAAI,CAACC,OAAO,CAACC,GAAG,CAACL,OAAOE,IAAI,KAAK,CAACD,QAAQK,SAAS,EAAE;YACvD,MAAM,IAAIH,MAAM,CAAC,IAAI,EAAEH,OAAOE,IAAI,CAAC,KAAK,CAAC;QAC3C;QAEA,QAAQ;QACR,MAAMK,qBAAmC;YACvCC,UAAU;YACVC,SAAS;YACT,GAAGT,MAAM;QACX;QAEA,OAAO;QACP,IAAIO,mBAAmBG,YAAY,EAAE;YACnC,MAAMC,cAAcJ,mBAAmBG,YAAY,CAACE,MAAM,CACxD,CAACC,MAAQ,CAAC,IAAI,CAACT,OAAO,CAACC,GAAG,CAACQ;YAE7B,IAAIF,YAAYG,MAAM,GAAG,GAAG;gBAC1B,MAAM,IAAIX,MACR,CAAC,IAAI,EAAEH,OAAOE,IAAI,CAAC,QAAQ,EAAES,YAAYI,IAAI,CAAC,OAAO;YAEzD;QACF;QAEA,OAAO;QACP,IAAI,CAACX,OAAO,CAACY,GAAG,CAAChB,OAAOE,IAAI,EAAE;YAC5BF,QAAQO;YACRU,QAAQ;YACRC,cAAcC,KAAKC,GAAG;QACxB;QAEAxB,OAAOyB,KAAK,CAAC,CAAC,SAAS,EAAErB,OAAOE,IAAI,EAAE;QAEtC,SAAS;QACT,IAAIK,mBAAmBe,KAAK,EAAEC,YAAY;YACxC,IAAI;gBACF,MAAMC,UAAyB;oBAC7BC,QAAQ,CAAC;oBACTC,MAAM;wBAAEC,OAAO9B,qBAAqB+B,QAAQ;oBAAC;gBAC/C;gBACArB,mBAAmBe,KAAK,CAACC,UAAU,CAACC;YACtC,EAAE,OAAOK,OAAO;gBACdjC,OAAOiC,KAAK,CAAC,CAAC,YAAY,EAAE7B,OAAOE,IAAI,EAAE,EAAE2B;YAC7C;QACF;QAEA,WAAW;QACX,OAAO;YACL,IAAI,CAACC,UAAU,CAAC9B,OAAOE,IAAI;QAC7B;IACF;IAEA;;;;;GAKC,GACD6B,cAAc3B,OAAuB,EAAEH,UAAiC,CAAC,CAAC,EAAQ;QAChF,UAAU;QACV,MAAM+B,gBAAgB,IAAI,CAACC,kBAAkB,CAAC7B;QAE9C4B,cAAcE,OAAO,CAAC,CAAClC;YACrB,IAAI,CAACD,QAAQ,CAACC,QAAQC;QACxB;IACF;IAEA;;GAEC,GACD,AAAQgC,mBAAmB7B,OAAuB,EAAkB;QAClE,MAAM+B,SAAyB,EAAE;QACjC,MAAMC,UAAU,IAAIC;QACpB,MAAMC,WAAW,IAAID;QAErB,MAAME,QAAQ,CAACvC;YACb,IAAIsC,SAASjC,GAAG,CAACL,OAAOE,IAAI,IAAI,KAAK;gBACnC,MAAM,IAAIC,MAAM,CAAC,SAAS,EAAEH,OAAOE,IAAI,EAAE;YAC3C;YAEA,IAAIkC,QAAQ/B,GAAG,CAACL,OAAOE,IAAI,IAAI,KAAK;gBAClC;YACF;YAEAoC,SAASE,GAAG,CAACxC,OAAOE,IAAI,IAAI;YAE5B,QAAQ;YACR,IAAIF,OAAOU,YAAY,EAAE;gBACvBV,OAAOU,YAAY,CAACwB,OAAO,CAAC,CAACO;oBAC3B,MAAM5B,MAAMT,QAAQsC,IAAI,CAAC,CAACC,IAAMA,EAAEzC,IAAI,KAAKuC;oBAC3C,IAAI5B,KAAK;wBACP0B,MAAM1B;oBACR;gBACF;YACF;YAEAyB,SAASM,MAAM,CAAC5C,OAAOE,IAAI,IAAI;YAC/BkC,QAAQI,GAAG,CAACxC,OAAOE,IAAI,IAAI;YAC3BiC,OAAOU,IAAI,CAAC7C;QACd;QAEAI,QAAQ8B,OAAO,CAAC,CAAClC;YACf,IAAI,CAACoC,QAAQ/B,GAAG,CAACL,OAAOE,IAAI,IAAI,KAAK;gBACnCqC,MAAMvC;YACR;QACF;QAEA,OAAOmC;IACT;IAEA;;;;GAIC,GACDL,WAAW5B,IAAY,EAAQ;QAC7B,MAAM4C,eAAe,IAAI,CAAC1C,OAAO,CAAC2C,GAAG,CAAC7C;QACtC,IAAI,CAAC4C,cAAc;YACjB;QACF;QAEA,SAAS;QACT,IAAIA,aAAa9C,MAAM,CAACsB,KAAK,EAAE0B,WAAW;YACxC,IAAI;gBACF,MAAMxB,UAAyB;oBAC7BC,QAAQ,CAAC;oBACTC,MAAM;wBAAEC,OAAO9B,qBAAqBoD,OAAO;oBAAC;gBAC9C;gBACAH,aAAa9C,MAAM,CAACsB,KAAK,CAAC0B,SAAS,CAACxB;YACtC,EAAE,OAAOK,OAAO;gBACdjC,OAAOiC,KAAK,CAAC,CAAC,YAAY,EAAE3B,MAAM,EAAE2B;YACtC;QACF;QAEA,IAAI,CAACzB,OAAO,CAACwC,MAAM,CAAC1C;QACpBN,OAAOyB,KAAK,CAAC,CAAC,WAAW,EAAEnB,MAAM;IACnC;IAEA;;;;;GAKC,GACD,MAAMgD,aAAavB,KAA2B,EAAEH,OAAsB,EAAiB;QACrF,iBAAiB;QACjB,MAAM2B,iBAAiBC,MAAMC,IAAI,CAAC,IAAI,CAACjD,OAAO,CAACkD,MAAM,IAClD1C,MAAM,CAAC,CAAC2C,MAAQA,IAAIvD,MAAM,CAACS,OAAO,KAAK,OACvC+C,IAAI,CAAC,CAACC,GAAGC,IAAM,AAACD,CAAAA,EAAEzD,MAAM,CAACQ,QAAQ,IAAI,GAAE,IAAMkD,CAAAA,EAAE1D,MAAM,CAACQ,QAAQ,IAAI,GAAE;QAEvE,WAAW;QACX,MAAMmD,UAA2F;YAC/F,CAAC9D,qBAAqB+B,QAAQ,CAAC,EAAE;YACjC,CAAC/B,qBAAqB+D,WAAW,CAAC,EAAE;YACpC,CAAC/D,qBAAqBgE,UAAU,CAAC,EAAE;YACnC,CAAChE,qBAAqBiE,gBAAgB,CAAC,EAAE;YACzC,CAACjE,qBAAqBkE,eAAe,CAAC,EAAE;YACxC,CAAClE,qBAAqBmE,YAAY,CAAC,EAAE;YACrC,CAACnE,qBAAqBoE,WAAW,CAAC,EAAE;YACpC,CAACpE,qBAAqBoD,OAAO,CAAC,EAAE;QAClC;QAEA,MAAMiB,WAAWP,OAAO,CAAChC,MAAM;QAC/B,IAAI,CAACuC,UAAU;YACb;QACF;QAEA,OAAO;QACP,KAAK,MAAMpB,gBAAgBK,eAAgB;YACzC,MAAMgB,OAAOrB,aAAa9C,MAAM,CAACsB,KAAK,EAAE,CAAC4C,SAAS;YAClD,IAAIC,MAAM;gBACR,IAAI;oBACF,MAAMA,KAAK3C;gBACb,EAAE,OAAOK,OAAO;oBACdjC,OAAOiC,KAAK,CAAC,CAAC,UAAU,EAAEiB,aAAa9C,MAAM,CAACE,IAAI,CAAC,CAAC,EAAEgE,UAAU,EAAErC;gBACpE;YACF;QACF;IACF;IAEA;;;;;GAKC,GACDuC,UAAUlE,IAAY,EAA4B;QAChD,OAAO,IAAI,CAACE,OAAO,CAAC2C,GAAG,CAAC7C,OAAOF;IACjC;IAEA;;;;GAIC,GACDqE,gBAAgC;QAC9B,OAAOjB,MAAMC,IAAI,CAAC,IAAI,CAACjD,OAAO,CAACkD,MAAM,IAAIgB,GAAG,CAAC,CAACf,MAAQA,IAAIvD,MAAM;IAClE;IAEA;;;;GAIC,GACDuE,oBAAoC;QAClC,OAAOnB,MAAMC,IAAI,CAAC,IAAI,CAACjD,OAAO,CAACkD,MAAM,IAClC1C,MAAM,CAAC,CAAC2C,MAAQA,IAAIvD,MAAM,CAACS,OAAO,KAAK,OACvC6D,GAAG,CAAC,CAACf,MAAQA,IAAIvD,MAAM;IAC5B;IAEA;;GAEC,GACDwE,QAAc;QACZ,cAAc;QACd,KAAK,MAAM,CAACtE,MAAM4C,aAAa,IAAI,IAAI,CAAC1C,OAAO,CAACqE,OAAO,GAAI;YACzD,IAAI3B,aAAa9C,MAAM,CAACsB,KAAK,EAAE0B,WAAW;gBACxC,IAAI;oBACF,MAAMxB,UAAyB;wBAC7BC,QAAQ,CAAC;wBACTC,MAAM;4BAAEC,OAAO9B,qBAAqBoD,OAAO;wBAAC;oBAC9C;oBACAH,aAAa9C,MAAM,CAACsB,KAAK,CAAC0B,SAAS,CAACxB;gBACtC,EAAE,OAAOK,OAAO;oBACdjC,OAAOiC,KAAK,CAAC,CAAC,YAAY,EAAE3B,MAAM,EAAE2B;gBACtC;YACF;QACF;QAEA,IAAI,CAACzB,OAAO,CAACoE,KAAK;QAClB5E,OAAOyB,KAAK,CAAC;IACf;IAEA;;;;GAIC,GACDqD,WAAmB;QACjB,OAAO,IAAI,CAACtE,OAAO,CAACuE,IAAI;IAC1B;;QA/PA,uBAAQvE,WAA2C,IAAIwE;;AAgQzD;AAEA;;CAEC,GACD,IAAIC,wBAAoD;AAExD,OAAO,SAASC;IACd,IAAI,CAACD,uBAAuB;QAC1BA,wBAAwB,IAAI/E;IAC9B;IACA,OAAO+E;AACT"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/router/plugin/RouterPluginManager.ts"],"sourcesContent":["/**\n * 路由插件管理器\n * 负责插件的注册、执行和生命周期管理\n */\n\nimport { logger } from '@vlian/logger';\nimport type { RouterPlugin, PluginContext, PluginRegisterOptions } from './types';\nimport { PluginLifecycleStage } from './types';\n\n/**\n * 插件状态\n */\ntype PluginStatus = 'registered' | 'initialized' | 'destroyed';\n\n/**\n * 插件注册信息\n */\ninterface PluginRegistration {\n /**\n * 插件实例\n */\n plugin: RouterPlugin;\n\n /**\n * 插件状态\n */\n status: PluginStatus;\n\n /**\n * 注册时间\n */\n registeredAt: number;\n}\n\n/**\n * 路由插件管理器\n */\nexport class RouterPluginManager {\n private plugins: Map<string, PluginRegistration> = new Map();\n\n /**\n * 注册插件\n * \n * @param plugin - 插件实例\n * @param options - 注册选项\n * @returns 取消注册函数\n */\n register(plugin: RouterPlugin, options: PluginRegisterOptions = {}): () => void {\n // 验证插件\n if (!plugin.name) {\n throw new Error('插件必须提供名称');\n }\n\n // 检查是否已存在\n if (this.plugins.has(plugin.name) && !options.overwrite) {\n throw new Error(`插件 \"${plugin.name}\" 已存在`);\n }\n\n // 设置默认值\n const pluginWithDefaults: RouterPlugin = {\n priority: 100,\n enabled: true,\n ...plugin,\n };\n\n // 检查依赖\n if (pluginWithDefaults.dependencies) {\n const missingDeps = pluginWithDefaults.dependencies.filter(\n (dep) => !this.plugins.has(dep)\n );\n if (missingDeps.length > 0) {\n throw new Error(\n `插件 \"${plugin.name}\" 缺少依赖: ${missingDeps.join(', ')}`\n );\n }\n }\n\n // 注册插件\n this.plugins.set(plugin.name, {\n plugin: pluginWithDefaults,\n status: 'registered',\n registeredAt: Date.now(),\n });\n\n logger.debug(`路由插件已注册: ${plugin.name}`);\n\n // 调用注册钩子\n if (pluginWithDefaults.hooks?.onRegister) {\n try {\n const context: PluginContext = {\n config: {} as any, // 在注册阶段可能还没有配置\n meta: { stage: PluginLifecycleStage.REGISTER },\n };\n pluginWithDefaults.hooks.onRegister(context);\n } catch (error) {\n logger.error(`插件注册钩子执行失败: ${plugin.name}`, error);\n }\n }\n\n // 返回取消注册函数\n return () => {\n this.unregister(plugin.name);\n };\n }\n\n /**\n * 批量注册插件\n * \n * @param plugins - 插件数组\n * @param options - 注册选项\n */\n registerBatch(plugins: RouterPlugin[], options: PluginRegisterOptions = {}): void {\n // 按依赖关系排序\n const sortedPlugins = this.sortByDependencies(plugins);\n\n sortedPlugins.forEach((plugin) => {\n this.register(plugin, options);\n });\n }\n\n /**\n * 按依赖关系排序插件(拓扑排序)\n */\n private sortByDependencies(plugins: RouterPlugin[]): RouterPlugin[] {\n const sorted: RouterPlugin[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n const visit = (plugin: RouterPlugin): void => {\n if (visiting.has(plugin.name || '')) {\n throw new Error(`检测到循环依赖: ${plugin.name}`);\n }\n\n if (visited.has(plugin.name || '')) {\n return;\n }\n\n visiting.add(plugin.name || '');\n\n // 先访问依赖\n if (plugin.dependencies) {\n plugin.dependencies.forEach((depName) => {\n const dep = plugins.find((p) => p.name === depName);\n if (dep) {\n visit(dep);\n }\n });\n }\n\n visiting.delete(plugin.name || '');\n visited.add(plugin.name || '');\n sorted.push(plugin);\n };\n\n plugins.forEach((plugin) => {\n if (!visited.has(plugin.name || '')) {\n visit(plugin);\n }\n });\n\n return sorted;\n }\n\n /**\n * 取消注册插件\n * \n * @param name - 插件名称\n */\n unregister(name: string): void {\n const registration = this.plugins.get(name);\n if (!registration) {\n return;\n }\n\n // 调用销毁钩子\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n\n this.plugins.delete(name);\n logger.debug(`路由插件已取消注册: ${name}`);\n }\n\n /**\n * 执行插件钩子\n * \n * @param stage - 生命周期阶段\n * @param context - 插件上下文\n */\n async executeHooks(stage: PluginLifecycleStage, context: PluginContext): Promise<void> {\n // 获取启用的插件并按优先级排序\n const enabledPlugins = Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .sort((a, b) => (a.plugin.priority || 100) - (b.plugin.priority || 100));\n\n // 根据阶段选择钩子\n const hookMap: Partial<Record<PluginLifecycleStage, keyof NonNullable<RouterPlugin['hooks']>>> = {\n [PluginLifecycleStage.REGISTER]: 'onRegister',\n [PluginLifecycleStage.BEFORE_INIT]: 'onBeforeInit',\n [PluginLifecycleStage.AFTER_INIT]: 'onAfterInit',\n [PluginLifecycleStage.BEFORE_TRANSFORM]: 'onBeforeTransform',\n [PluginLifecycleStage.AFTER_TRANSFORM]: 'onAfterTransform',\n [PluginLifecycleStage.BEFORE_MATCH]: 'onBeforeMatch',\n [PluginLifecycleStage.AFTER_MATCH]: 'onAfterMatch',\n [PluginLifecycleStage.DESTROY]: 'onDestroy',\n };\n\n const hookName = hookMap[stage];\n if (!hookName) {\n return;\n }\n\n // 执行钩子\n for (const registration of enabledPlugins) {\n const hook = registration.plugin.hooks?.[hookName];\n if (hook) {\n try {\n await hook(context);\n } catch (error) {\n logger.error(`插件钩子执行失败: ${registration.plugin.name}.${hookName}`, error);\n }\n }\n }\n }\n\n /**\n * 获取插件\n * \n * @param name - 插件名称\n * @returns 插件实例,如果不存在返回 undefined\n */\n getPlugin(name: string): RouterPlugin | undefined {\n return this.plugins.get(name)?.plugin;\n }\n\n /**\n * 获取所有插件\n * \n * @returns 插件数组\n */\n getAllPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values()).map((reg) => reg.plugin);\n }\n\n /**\n * 获取启用的插件\n * \n * @returns 启用的插件数组\n */\n getEnabledPlugins(): RouterPlugin[] {\n return Array.from(this.plugins.values())\n .filter((reg) => reg.plugin.enabled !== false)\n .map((reg) => reg.plugin);\n }\n\n /**\n * 清空所有插件\n */\n clear(): void {\n // 调用所有插件的销毁钩子\n for (const [name, registration] of this.plugins.entries()) {\n if (registration.plugin.hooks?.onDestroy) {\n try {\n const context: PluginContext = {\n config: {} as any,\n meta: { stage: PluginLifecycleStage.DESTROY },\n };\n registration.plugin.hooks.onDestroy(context);\n } catch (error) {\n logger.error(`插件销毁钩子执行失败: ${name}`, error);\n }\n }\n }\n\n this.plugins.clear();\n logger.debug('所有路由插件已清空');\n }\n\n /**\n * 获取插件数量\n * \n * @returns 插件数量\n */\n getCount(): number {\n return this.plugins.size;\n }\n}\n\n/**\n * 获取路由插件管理器单例\n */\nlet pluginManagerInstance: RouterPluginManager | null = null;\n\nexport function getRouterPluginManager(): RouterPluginManager {\n if (!pluginManagerInstance) {\n pluginManagerInstance = new RouterPluginManager();\n }\n return pluginManagerInstance;\n}\n"],"names":["logger","PluginLifecycleStage","RouterPluginManager","register","plugin","options","name","Error","plugins","has","overwrite","pluginWithDefaults","priority","enabled","dependencies","missingDeps","filter","dep","length","join","set","status","registeredAt","Date","now","debug","hooks","onRegister","context","config","meta","stage","REGISTER","error","unregister","registerBatch","sortedPlugins","sortByDependencies","forEach","sorted","visited","Set","visiting","visit","add","depName","find","p","delete","push","registration","get","onDestroy","DESTROY","executeHooks","enabledPlugins","Array","from","values","reg","sort","a","b","hookMap","BEFORE_INIT","AFTER_INIT","BEFORE_TRANSFORM","AFTER_TRANSFORM","BEFORE_MATCH","AFTER_MATCH","hookName","hook","getPlugin","getAllPlugins","map","getEnabledPlugins","clear","entries","getCount","size","Map","pluginManagerInstance","getRouterPluginManager"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ Object.defineProperty(exports, "transformRoutesToReactRoutes", {
|
|
|
11
11
|
const _jsxruntime = require("react/jsx-runtime");
|
|
12
12
|
const _reactrouterdom = require("react-router-dom");
|
|
13
13
|
const _RouteErrorBoundary = require("./RouteErrorBoundary");
|
|
14
|
-
const
|
|
14
|
+
const _logger = require("@vlian/logger");
|
|
15
15
|
function DefaultRouteHydrateFallback() {
|
|
16
16
|
return /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
17
17
|
style: {
|
|
@@ -78,7 +78,7 @@ const transformRoutesToReactRoutes = async (routes, transformResult, defaultRout
|
|
|
78
78
|
const { action, loader, shouldRevalidate, default: Component } = m;
|
|
79
79
|
// 如果 Component 不存在,记录警告
|
|
80
80
|
if (!Component) {
|
|
81
|
-
|
|
81
|
+
_logger.logger.warn(`路由组件未找到 default 导出: ${name}`, m);
|
|
82
82
|
}
|
|
83
83
|
return {
|
|
84
84
|
action,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/core/router/utils/adapters/react-router/transform.tsx"],"sourcesContent":["import type { RouteConfig } from '../../../types';\nimport {\n type RouteObject,\n Navigate\n} from 'react-router-dom';\nimport type { TransformRoutesResult } from '../../transform';\nimport { RouteErrorBoundary } from './RouteErrorBoundary';\nimport type { ComponentImport } from '../../../types';\nimport { logger } from '../../../../../utils';\n\nfunction DefaultRouteHydrateFallback() {\n return (\n <div style={{ padding: 16, textAlign: 'center', color: '#5f6c7b' }}>\n Loading...\n </div>\n );\n}\n\nexport const transformRoutesToReactRoutes = async (\n routes: RouteConfig[],\n transformResult: TransformRoutesResult,\n defaultRouteErrorComponent?: ComponentImport,\n defaultRouteLoadingComponent?: ComponentImport,\n enableHydrateFallback: boolean = false,\n): Promise<RouteObject[]> => {\n\n /**\n * 批量处理路由\n * @param routes 路由组\n */\n function transformRouteToReactRoutes(routes: RouteConfig[]) {\n return routes.flatMap((route: RouteConfig) => transformRouteToReactRoute(route))\n }\n\n /**\n * 处理单个路由\n * @param route 路由\n */\n function transformRouteToReactRoute(route: RouteConfig): RouteObject {\n const {\n isGroup = false,\n enableRedirection = false,\n name,\n path,\n handle,\n children,\n page,\n layout,\n error,\n errors,\n loading,\n } = route;\n const routeError = error ?? errors;\n\n // 获取错误组件\n async function getErrorComponent() {\n // 如果 error/errors 是函数,直接使用\n if (typeof routeError === 'function') {\n return routeError();\n }\n\n const errorsMap = transformResult.errors;\n\n // 判断 error/errors 是否为 string 且不是空字符串\n if (typeof routeError === 'string' && routeError !== '') {\n // 使用 routeError 作为 key 获取 transformResult.errors 的值\n const errorResolver = errorsMap.get(routeError);\n\n // 如果获取不到,返回 null\n if (!errorResolver) {\n return null;\n }\n\n // 如果获取到,返回对应的值(调用动态导入函数)\n if (typeof errorResolver === 'function') {\n return errorResolver();\n }\n\n return null;\n }\n\n // 如果 errors 为空,使用配置的默认错误组件或内置的 RouteErrorBoundary 组件\n if (defaultRouteErrorComponent) {\n // 如果配置了默认错误组件,使用配置的组件\n return defaultRouteErrorComponent();\n }\n\n // 如果没有配置默认错误组件,使用内置的 RouteErrorBoundary 组件\n // 直接导入而非懒加载,因为:\n // 1. RouteErrorBoundary 是框架核心组件,体积小\n // 2. 错误边界需要快速响应,直接导入速度更快\n // 3. 作为基础设施组件,应该保证可用性\n return { default: RouteErrorBoundary };\n }\n\n // 获取转换配置\n function convertConfig(m: any) {\n if (!m) {\n return null;\n }\n const { action, loader, shouldRevalidate, default: Component } = m;\n\n // 如果 Component 不存在,记录警告\n if (!Component) {\n logger.warn(`路由组件未找到 default 导出: ${name}`, m);\n }\n\n return {\n action, // always use action\n loader, // always use loader\n shouldRevalidate,\n Component\n };\n }\n\n // 获取加载组件\n async function getLoadingComponent() {\n if (typeof loading === 'function') {\n return loading();\n }\n\n if (typeof loading === 'string' && loading !== '') {\n const loadingResolver = transformResult.loadings.get(loading);\n if (typeof loadingResolver === 'function') {\n return loadingResolver();\n }\n }\n\n if (defaultRouteLoadingComponent) {\n return defaultRouteLoadingComponent();\n }\n\n return null;\n }\n\n // 获取配置\n async function getConfig(index: boolean = false) {\n // 如果有layout和不是index,返回布局配置\n if (layout && !index) {\n // 如果 layout 是函数,直接使用\n if (typeof layout === 'function') {\n const config = await layout();\n return convertConfig(config);\n }\n\n // 如果 layout 是字符串,从 Map 中获取\n if (typeof layout === 'string') {\n const layoutResolver = transformResult.layouts.get(layout);\n if (!layoutResolver) {\n throw new Error(`未找到名为 ${layout} 的布局组件`);\n }\n const config = await layoutResolver();\n return convertConfig(config);\n }\n }\n\n let pageName = name;\n\n // 如果是notFound则转成404\n if (pageName === 'notFound') {\n pageName = '404'\n }\n\n if (page && (!children?.length || index)) {\n // 如果 page 是函数,直接使用\n if (typeof page === 'function') {\n const config = await page();\n return convertConfig(config);\n }\n\n // 如果 page 是字符串,从 Map 中获取\n if (typeof page === 'string') {\n const viewResolver = transformResult.pages.get(page);\n if (!viewResolver) {\n throw new Error(`未找到名为 ${page} 的页面组件`);\n }\n const config = await viewResolver();\n return convertConfig(config);\n }\n }\n\n return null;\n }\n\n // 获取处理信息,即额外的配置信息\n function getHandle(index: boolean = false) {\n if ((layout || isGroup) && !index) {\n return null\n }\n return {\n ...handle,\n name,\n path\n }\n }\n\n\n const reactRoute: RouteObject = {\n children: [],\n id: name,\n handle: getHandle(),\n lazy: async () => {\n const ErrorBoundary = await getErrorComponent();\n const config = await getConfig();\n const LoadingComponent = await getLoadingComponent();\n const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;\n\n // 如果配置为空,确保至少返回一个空对象,避免展开 undefined\n if (!config) {\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n };\n }\n\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n ...config\n };\n },\n path\n };\n\n if (enableHydrateFallback) {\n reactRoute.hydrateFallbackElement = <DefaultRouteHydrateFallback />;\n }\n\n // 处理子路由\n if (children?.length) {\n reactRoute.children = children.flatMap(child => transformRouteToReactRoute(child)).sort((a, b) => {\n const orderA = a.handle?.order ?? 99;\n const orderB = b.handle?.order ?? 99;\n return orderA - orderB;\n });\n\n if (page && !isGroup) {\n reactRoute.children.unshift({\n handle: getHandle(true),\n index: true,\n lazy: async () => {\n const ErrorBoundary = await getErrorComponent();\n const LoadingComponent = await getLoadingComponent();\n const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;\n const Component = page;\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n Component,\n ...(await getConfig(true))\n };\n }\n });\n }\n\n if (enableRedirection && isGroup) {\n const [firstChild] = reactRoute.children;\n if (firstChild?.path) {\n reactRoute.children.unshift({\n index: true,\n handle: getHandle(true),\n element: <Navigate to={firstChild.path as string} replace />\n });\n }\n }\n\n }\n // 若存在 layout 且没有子路由,但同时声明了 page,则自动生成 index 子路由以渲染页面\n // 场景:/test 使用自定义 layout,且没有 children 时仍应渲染 page\n if ((!children || children.length === 0) && layout && page && !isGroup) {\n reactRoute.children = [{\n handle: getHandle(true),\n index: true,\n lazy: async () => {\n const ErrorBoundary = await getErrorComponent();\n const LoadingComponent = await getLoadingComponent();\n const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;\n const Component = page;\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n Component,\n ...(await getConfig(true))\n };\n }\n }];\n }\n\n return reactRoute;\n }\n\n return transformRouteToReactRoutes(routes);\n}\n"],"names":["transformRoutesToReactRoutes","DefaultRouteHydrateFallback","div","style","padding","textAlign","color","routes","transformResult","defaultRouteErrorComponent","defaultRouteLoadingComponent","enableHydrateFallback","transformRouteToReactRoutes","flatMap","route","transformRouteToReactRoute","isGroup","enableRedirection","name","path","handle","children","page","layout","error","errors","loading","routeError","getErrorComponent","errorsMap","errorResolver","get","default","RouteErrorBoundary","convertConfig","m","action","loader","shouldRevalidate","Component","logger","warn","getLoadingComponent","loadingResolver","loadings","getConfig","index","config","layoutResolver","layouts","Error","pageName","length","viewResolver","pages","getHandle","reactRoute","id","lazy","ErrorBoundary","LoadingComponent","HydrateFallback","hydrateFallbackElement","child","sort","a","b","orderA","order","orderB","unshift","firstChild","element","Navigate","to","replace"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/router/utils/adapters/react-router/transform.tsx"],"sourcesContent":["import type { RouteConfig } from '../../../types';\nimport {\n type RouteObject,\n Navigate\n} from 'react-router-dom';\nimport type { TransformRoutesResult } from '../../transform';\nimport { RouteErrorBoundary } from './RouteErrorBoundary';\nimport type { ComponentImport } from '../../../types';\nimport { logger } from '@vlian/logger';\n\nfunction DefaultRouteHydrateFallback() {\n return (\n <div style={{ padding: 16, textAlign: 'center', color: '#5f6c7b' }}>\n Loading...\n </div>\n );\n}\n\nexport const transformRoutesToReactRoutes = async (\n routes: RouteConfig[],\n transformResult: TransformRoutesResult,\n defaultRouteErrorComponent?: ComponentImport,\n defaultRouteLoadingComponent?: ComponentImport,\n enableHydrateFallback: boolean = false,\n): Promise<RouteObject[]> => {\n\n /**\n * 批量处理路由\n * @param routes 路由组\n */\n function transformRouteToReactRoutes(routes: RouteConfig[]) {\n return routes.flatMap((route: RouteConfig) => transformRouteToReactRoute(route))\n }\n\n /**\n * 处理单个路由\n * @param route 路由\n */\n function transformRouteToReactRoute(route: RouteConfig): RouteObject {\n const {\n isGroup = false,\n enableRedirection = false,\n name,\n path,\n handle,\n children,\n page,\n layout,\n error,\n errors,\n loading,\n } = route;\n const routeError = error ?? errors;\n\n // 获取错误组件\n async function getErrorComponent() {\n // 如果 error/errors 是函数,直接使用\n if (typeof routeError === 'function') {\n return routeError();\n }\n\n const errorsMap = transformResult.errors;\n\n // 判断 error/errors 是否为 string 且不是空字符串\n if (typeof routeError === 'string' && routeError !== '') {\n // 使用 routeError 作为 key 获取 transformResult.errors 的值\n const errorResolver = errorsMap.get(routeError);\n\n // 如果获取不到,返回 null\n if (!errorResolver) {\n return null;\n }\n\n // 如果获取到,返回对应的值(调用动态导入函数)\n if (typeof errorResolver === 'function') {\n return errorResolver();\n }\n\n return null;\n }\n\n // 如果 errors 为空,使用配置的默认错误组件或内置的 RouteErrorBoundary 组件\n if (defaultRouteErrorComponent) {\n // 如果配置了默认错误组件,使用配置的组件\n return defaultRouteErrorComponent();\n }\n\n // 如果没有配置默认错误组件,使用内置的 RouteErrorBoundary 组件\n // 直接导入而非懒加载,因为:\n // 1. RouteErrorBoundary 是框架核心组件,体积小\n // 2. 错误边界需要快速响应,直接导入速度更快\n // 3. 作为基础设施组件,应该保证可用性\n return { default: RouteErrorBoundary };\n }\n\n // 获取转换配置\n function convertConfig(m: any) {\n if (!m) {\n return null;\n }\n const { action, loader, shouldRevalidate, default: Component } = m;\n\n // 如果 Component 不存在,记录警告\n if (!Component) {\n logger.warn(`路由组件未找到 default 导出: ${name}`, m);\n }\n\n return {\n action, // always use action\n loader, // always use loader\n shouldRevalidate,\n Component\n };\n }\n\n // 获取加载组件\n async function getLoadingComponent() {\n if (typeof loading === 'function') {\n return loading();\n }\n\n if (typeof loading === 'string' && loading !== '') {\n const loadingResolver = transformResult.loadings.get(loading);\n if (typeof loadingResolver === 'function') {\n return loadingResolver();\n }\n }\n\n if (defaultRouteLoadingComponent) {\n return defaultRouteLoadingComponent();\n }\n\n return null;\n }\n\n // 获取配置\n async function getConfig(index: boolean = false) {\n // 如果有layout和不是index,返回布局配置\n if (layout && !index) {\n // 如果 layout 是函数,直接使用\n if (typeof layout === 'function') {\n const config = await layout();\n return convertConfig(config);\n }\n\n // 如果 layout 是字符串,从 Map 中获取\n if (typeof layout === 'string') {\n const layoutResolver = transformResult.layouts.get(layout);\n if (!layoutResolver) {\n throw new Error(`未找到名为 ${layout} 的布局组件`);\n }\n const config = await layoutResolver();\n return convertConfig(config);\n }\n }\n\n let pageName = name;\n\n // 如果是notFound则转成404\n if (pageName === 'notFound') {\n pageName = '404'\n }\n\n if (page && (!children?.length || index)) {\n // 如果 page 是函数,直接使用\n if (typeof page === 'function') {\n const config = await page();\n return convertConfig(config);\n }\n\n // 如果 page 是字符串,从 Map 中获取\n if (typeof page === 'string') {\n const viewResolver = transformResult.pages.get(page);\n if (!viewResolver) {\n throw new Error(`未找到名为 ${page} 的页面组件`);\n }\n const config = await viewResolver();\n return convertConfig(config);\n }\n }\n\n return null;\n }\n\n // 获取处理信息,即额外的配置信息\n function getHandle(index: boolean = false) {\n if ((layout || isGroup) && !index) {\n return null\n }\n return {\n ...handle,\n name,\n path\n }\n }\n\n\n const reactRoute: RouteObject = {\n children: [],\n id: name,\n handle: getHandle(),\n lazy: async () => {\n const ErrorBoundary = await getErrorComponent();\n const config = await getConfig();\n const LoadingComponent = await getLoadingComponent();\n const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;\n\n // 如果配置为空,确保至少返回一个空对象,避免展开 undefined\n if (!config) {\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n };\n }\n\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n ...config\n };\n },\n path\n };\n\n if (enableHydrateFallback) {\n reactRoute.hydrateFallbackElement = <DefaultRouteHydrateFallback />;\n }\n\n // 处理子路由\n if (children?.length) {\n reactRoute.children = children.flatMap(child => transformRouteToReactRoute(child)).sort((a, b) => {\n const orderA = a.handle?.order ?? 99;\n const orderB = b.handle?.order ?? 99;\n return orderA - orderB;\n });\n\n if (page && !isGroup) {\n reactRoute.children.unshift({\n handle: getHandle(true),\n index: true,\n lazy: async () => {\n const ErrorBoundary = await getErrorComponent();\n const LoadingComponent = await getLoadingComponent();\n const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;\n const Component = page;\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n Component,\n ...(await getConfig(true))\n };\n }\n });\n }\n\n if (enableRedirection && isGroup) {\n const [firstChild] = reactRoute.children;\n if (firstChild?.path) {\n reactRoute.children.unshift({\n index: true,\n handle: getHandle(true),\n element: <Navigate to={firstChild.path as string} replace />\n });\n }\n }\n\n }\n // 若存在 layout 且没有子路由,但同时声明了 page,则自动生成 index 子路由以渲染页面\n // 场景:/test 使用自定义 layout,且没有 children 时仍应渲染 page\n if ((!children || children.length === 0) && layout && page && !isGroup) {\n reactRoute.children = [{\n handle: getHandle(true),\n index: true,\n lazy: async () => {\n const ErrorBoundary = await getErrorComponent();\n const LoadingComponent = await getLoadingComponent();\n const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;\n const Component = page;\n return {\n ErrorBoundary: ErrorBoundary?.default,\n HydrateFallback,\n Component,\n ...(await getConfig(true))\n };\n }\n }];\n }\n\n return reactRoute;\n }\n\n return transformRouteToReactRoutes(routes);\n}\n"],"names":["transformRoutesToReactRoutes","DefaultRouteHydrateFallback","div","style","padding","textAlign","color","routes","transformResult","defaultRouteErrorComponent","defaultRouteLoadingComponent","enableHydrateFallback","transformRouteToReactRoutes","flatMap","route","transformRouteToReactRoute","isGroup","enableRedirection","name","path","handle","children","page","layout","error","errors","loading","routeError","getErrorComponent","errorsMap","errorResolver","get","default","RouteErrorBoundary","convertConfig","m","action","loader","shouldRevalidate","Component","logger","warn","getLoadingComponent","loadingResolver","loadings","getConfig","index","config","layoutResolver","layouts","Error","pageName","length","viewResolver","pages","getHandle","reactRoute","id","lazy","ErrorBoundary","LoadingComponent","HydrateFallback","hydrateFallbackElement","child","sort","a","b","orderA","order","orderB","unshift","firstChild","element","Navigate","to","replace"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Navigate } from "react-router-dom";
|
|
3
3
|
import { RouteErrorBoundary } from "./RouteErrorBoundary";
|
|
4
|
-
import { logger } from "
|
|
4
|
+
import { logger } from "@vlian/logger";
|
|
5
5
|
function DefaultRouteHydrateFallback() {
|
|
6
6
|
return /*#__PURE__*/ _jsx("div", {
|
|
7
7
|
style: {
|