@vlian/framework 1.2.16 → 1.2.19
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/router/RouterManager.cjs +52 -3
- package/dist/core/router/RouterManager.cjs.map +1 -1
- package/dist/core/router/RouterManager.d.ts +5 -0
- package/dist/core/router/RouterManager.js +53 -4
- package/dist/core/router/RouterManager.js.map +1 -1
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.cjs +1 -1
- 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/dev/RouterDevTools.cjs.map +1 -1
- package/dist/core/router/dev/RouterDevTools.js.map +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.cjs +24 -4
- package/dist/core/router/middleware/RouterMiddlewareManager.cjs.map +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.d.ts +1 -0
- package/dist/core/router/middleware/RouterMiddlewareManager.js +24 -4
- package/dist/core/router/middleware/RouterMiddlewareManager.js.map +1 -1
- package/dist/core/router/middleware/types.cjs.map +1 -1
- package/dist/core/router/middleware/types.d.ts +1 -1
- package/dist/core/router/middleware/types.js.map +1 -1
- package/dist/core/router/navigation/RouterNavigation.cjs +69 -14
- package/dist/core/router/navigation/RouterNavigation.cjs.map +1 -1
- package/dist/core/router/navigation/RouterNavigation.d.ts +3 -0
- package/dist/core/router/navigation/RouterNavigation.js +69 -14
- package/dist/core/router/navigation/RouterNavigation.js.map +1 -1
- package/dist/core/router/performance/RouteCache.cjs +34 -13
- package/dist/core/router/performance/RouteCache.cjs.map +1 -1
- package/dist/core/router/performance/RouteCache.d.ts +8 -2
- package/dist/core/router/performance/RouteCache.js +34 -13
- package/dist/core/router/performance/RouteCache.js.map +1 -1
- package/dist/core/router/performance/RoutePreloader.cjs +89 -22
- package/dist/core/router/performance/RoutePreloader.cjs.map +1 -1
- package/dist/core/router/performance/RoutePreloader.d.ts +9 -1
- package/dist/core/router/performance/RoutePreloader.js +89 -22
- package/dist/core/router/performance/RoutePreloader.js.map +1 -1
- package/dist/core/router/types.d.ts +31 -5
- package/dist/core/router/types.js.map +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.cjs +43 -65
- package/dist/core/router/utils/adapters/react-router/transform.cjs.map +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.d.ts +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.js +43 -60
- package/dist/core/router/utils/adapters/react-router/transform.js.map +1 -1
- package/dist/core/router/utils/transform.cjs +79 -70
- package/dist/core/router/utils/transform.cjs.map +1 -1
- package/dist/core/router/utils/transform.d.ts +1 -1
- package/dist/core/router/utils/transform.js +80 -71
- package/dist/core/router/utils/transform.js.map +1 -1
- package/dist/core/router/validation/RouterConfigValidator.d.ts +68 -4
- package/dist/core/router/validation/schema.cjs +72 -2
- package/dist/core/router/validation/schema.cjs.map +1 -1
- package/dist/core/router/validation/schema.d.ts +105 -6
- package/dist/core/router/validation/schema.js +72 -2
- package/dist/core/router/validation/schema.js.map +1 -1
- package/dist/index.umd.js +705 -431
- package/dist/index.umd.js.map +1 -1
- package/dist/request.umd.js +1 -1
- package/dist/state.umd.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/router/navigation/RouterNavigation.ts"],"sourcesContent":["/**\n * 路由导航 API\n * 提供框架级别的路由导航能力,封装 react-router-dom 的导航功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteLocation, NavigateOptions } from '../types';\nimport { getRouterLifecycleManager } from '../lifecycle';\nimport { getRouterMiddlewareManager } from '../middleware';\nimport type { RouterMiddlewareContext } from '../middleware/types';\n\n/**\n * 路由导航器\n */\nexport class RouterNavigation {\n /**\n * 导航到指定路径\n * \n * @param to - 目标路径或路由名称\n * @param options - 导航选项\n */\n static async navigate(\n to: string,\n options?: NavigateOptions\n ): Promise<void> {\n const routerManager = await import('../RouterManager').then((m) => m.getRouterManager());\n const router = routerManager.getRouter();\n\n if (!router) {\n throw new Error('路由未初始化,无法导航');\n }\n\n // 获取当前路由信息\n const currentLocation = this.getCurrentRoute();\n\n // 构建目标路由位置\n const targetLocation: RouteLocation = {\n path: to,\n query: options?.query,\n };\n\n // 执行生命周期钩子\n const lifecycleManager = getRouterLifecycleManager();\n const beforeEachResult = await lifecycleManager.beforeEach(\n targetLocation,\n currentLocation\n );\n\n // 如果 beforeEach 返回 false,阻止导航\n if (beforeEachResult === false) {\n logger.debug('路由导航被阻止: beforeEach 返回 false');\n return;\n }\n\n // 如果 beforeEach 返回字符串,重定向到该路径\n if (typeof beforeEachResult === 'string') {\n logger.debug(`路由导航重定向: ${beforeEachResult}`);\n to = beforeEachResult;\n }\n\n // 执行中间件\n const middlewareManager = getRouterMiddlewareManager();\n const middlewareContext: RouterMiddlewareContext = {\n to: {\n ...targetLocation,\n path: to,\n },\n from: currentLocation,\n options,\n };\n\n const middlewareResult = await middlewareManager.execute(middlewareContext);\n\n // 如果中间件阻止导航\n if (!middlewareResult.allow) {\n if (middlewareResult.redirect) {\n logger.debug(`路由导航被中间件重定向: ${middlewareResult.redirect}`);\n // 递归调用 navigate 进行重定向\n return this.navigate(middlewareResult.redirect, options);\n }\n logger.debug(`路由导航被中间件阻止: ${middlewareResult.reason || '未知原因'}`);\n return;\n }\n\n // 执行导航\n try {\n if (options?.replace) {\n router.navigate(to, { replace: true, state: options.state });\n } else {\n router.navigate(to, { state: options?.state });\n }\n\n // 执行 afterEach 钩子\n await lifecycleManager.afterEach(\n {\n ...targetLocation,\n path: to,\n },\n currentLocation\n );\n } catch (error) {\n logger.error('路由导航失败', error);\n throw error;\n }\n }\n\n /**\n * 获取当前路由信息\n * \n * @returns 当前路由位置信息\n */\n static getCurrentRoute(): RouteLocation {\n // 从 window.location 获取当前路由信息\n const pathname = window.location.pathname;\n const search = window.location.search;\n const hash = window.location.hash;\n\n // 解析查询参数\n const query: Record<string, unknown> = {};\n if (search) {\n const params = new URLSearchParams(search);\n params.forEach((value, key) => {\n query[key] = value;\n });\n }\n\n return {\n path: pathname + hash,\n query,\n };\n }\n\n /**\n * 返回上一页\n * \n * @param fallback - 如果没有历史记录,跳转到该路径\n */\n static async goBack(fallback?: string): Promise<void> {\n if (window.history.length > 1) {\n window.history.back();\n } else if (fallback) {\n await this.navigate(fallback);\n } else {\n logger.warn('没有历史记录,无法返回');\n }\n }\n\n /**\n * 前进到下一页\n */\n static goForward(): void {\n window.history.forward();\n }\n\n /**\n * 替换当前路由\n * \n * @param to - 目标路径\n * @param options - 导航选项\n */\n static async replace(\n to: string,\n options?: Omit<NavigateOptions, 'replace'>\n ): Promise<void> {\n return this.navigate(to, { ...options, replace: true });\n }\n}\n"],"names":["logger","getRouterLifecycleManager","getRouterMiddlewareManager","RouterNavigation","navigate","to","options","routerManager","then","m","getRouterManager","router","getRouter","Error","currentLocation","getCurrentRoute","targetLocation","path","query","lifecycleManager","beforeEachResult","beforeEach","debug","middlewareManager","middlewareContext","from","middlewareResult","execute","allow","redirect","reason","replace","state","afterEach","error","pathname","window","location","search","hash","params","URLSearchParams","forEach","value","key","goBack","fallback","history","length","back","warn","goForward","forward"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/router/navigation/RouterNavigation.ts"],"sourcesContent":["/**\n * 路由导航 API\n * 提供框架级别的路由导航能力,封装 react-router-dom 的导航功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteLocation, NavigateOptions } from '../types';\nimport { getRouterLifecycleManager } from '../lifecycle';\nimport { getRouterMiddlewareManager } from '../middleware';\nimport type { RouterMiddlewareContext } from '../middleware/types';\n\n/**\n * 路由导航器\n */\nexport class RouterNavigation {\n private static readonly MAX_REDIRECTS = 10;\n\n private static buildTargetPath(\n to: string,\n query?: Record<string, unknown>\n ): string {\n const base =\n typeof window !== 'undefined' && window.location?.origin\n ? window.location.origin\n : 'http://localhost';\n\n const url = new URL(to, base);\n\n if (query && Object.keys(query).length > 0) {\n const params = new URLSearchParams(url.search);\n Object.entries(query).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n params.delete(key);\n return;\n }\n params.set(key, String(value));\n });\n url.search = params.toString();\n }\n\n return `${url.pathname}${url.search}${url.hash}`;\n }\n\n private static async navigateInternal(\n to: string,\n options: NavigateOptions | undefined,\n depth: number,\n visited: Set<string>\n ): Promise<void> {\n const startTime = performance.now();\n\n if (depth > this.MAX_REDIRECTS) {\n throw new Error(`路由重定向次数超过上限(${this.MAX_REDIRECTS}),可能存在循环重定向`);\n }\n\n const targetPath = this.buildTargetPath(to, options?.query);\n if (visited.has(targetPath)) {\n throw new Error(`检测到循环重定向: ${targetPath}`);\n }\n visited.add(targetPath);\n\n const routerManager = await import('../RouterManager').then((m) => m.getRouterManager());\n const router = routerManager.getRouter();\n\n if (!router) {\n throw new Error('路由未初始化,无法导航');\n }\n\n // 获取当前路由信息\n const currentLocation = this.getCurrentRoute();\n\n // 构建目标路由位置\n const targetLocation: RouteLocation = {\n path: targetPath,\n query: options?.query,\n };\n\n // 执行生命周期钩子\n const lifecycleManager = getRouterLifecycleManager();\n const beforeEachResult = await lifecycleManager.beforeEach(\n targetLocation,\n currentLocation\n );\n\n let finalPath = targetPath;\n\n // 如果 beforeEach 返回 false,阻止导航\n if (beforeEachResult === false) {\n logger.debug('路由导航被阻止: beforeEach 返回 false');\n return;\n }\n\n // 如果 beforeEach 返回字符串,重定向到该路径\n if (typeof beforeEachResult === 'string') {\n logger.debug(`路由导航重定向: ${beforeEachResult}`);\n finalPath = this.buildTargetPath(beforeEachResult);\n }\n\n // 执行中间件\n const middlewareManager = getRouterMiddlewareManager();\n const middlewareContext: RouterMiddlewareContext = {\n to: {\n ...targetLocation,\n path: finalPath,\n },\n from: currentLocation,\n options,\n };\n\n const middlewareResult = await middlewareManager.execute(middlewareContext);\n\n // 如果中间件阻止导航\n if (!middlewareResult.allow) {\n if (middlewareResult.redirect) {\n logger.debug(`路由导航被中间件重定向: ${middlewareResult.redirect}`);\n return this.navigateInternal(\n middlewareResult.redirect,\n { ...options, query: undefined },\n depth + 1,\n visited\n );\n }\n logger.debug(`路由导航被中间件阻止: ${middlewareResult.reason || '未知原因'}`);\n return;\n }\n\n // 执行导航\n try {\n if (options?.replace) {\n router.navigate(finalPath, { replace: true, state: options.state });\n } else {\n router.navigate(finalPath, { state: options?.state });\n }\n\n // 执行 afterEach 钩子\n await lifecycleManager.afterEach(\n {\n ...targetLocation,\n path: finalPath,\n },\n currentLocation\n );\n\n const duration = performance.now() - startTime;\n routerManager.getMonitoring().trackRoutePerformance(finalPath, {\n totalTime: duration,\n });\n } catch (error) {\n logger.error('路由导航失败', error);\n throw error;\n }\n }\n\n /**\n * 导航到指定路径\n * \n * @param to - 目标路径或路由名称\n * @param options - 导航选项\n */\n static async navigate(\n to: string,\n options?: NavigateOptions\n ): Promise<void> {\n return this.navigateInternal(to, options, 0, new Set());\n }\n\n /**\n * 获取当前路由信息\n * \n * @returns 当前路由位置信息\n */\n static getCurrentRoute(): RouteLocation {\n if (typeof window === 'undefined') {\n return {\n path: '/',\n query: {},\n };\n }\n\n // 从 window.location 获取当前路由信息\n const pathname = window.location.pathname;\n const search = window.location.search;\n const hash = window.location.hash;\n\n // 解析查询参数\n const query: Record<string, unknown> = {};\n if (search) {\n const params = new URLSearchParams(search);\n params.forEach((value, key) => {\n query[key] = value;\n });\n }\n\n return {\n path: pathname + hash,\n query,\n };\n }\n\n /**\n * 返回上一页\n * \n * @param fallback - 如果没有历史记录,跳转到该路径\n */\n static async goBack(fallback?: string): Promise<void> {\n if (window.history.length > 1) {\n window.history.back();\n } else if (fallback) {\n await this.navigate(fallback);\n } else {\n logger.warn('没有历史记录,无法返回');\n }\n }\n\n /**\n * 前进到下一页\n */\n static goForward(): void {\n window.history.forward();\n }\n\n /**\n * 替换当前路由\n * \n * @param to - 目标路径\n * @param options - 导航选项\n */\n static async replace(\n to: string,\n options?: Omit<NavigateOptions, 'replace'>\n ): Promise<void> {\n return this.navigate(to, { ...options, replace: true });\n }\n}\n"],"names":["logger","getRouterLifecycleManager","getRouterMiddlewareManager","RouterNavigation","buildTargetPath","to","query","base","window","location","origin","url","URL","Object","keys","length","params","URLSearchParams","search","entries","forEach","key","value","undefined","delete","set","String","toString","pathname","hash","navigateInternal","options","depth","visited","startTime","performance","now","MAX_REDIRECTS","Error","targetPath","has","add","routerManager","then","m","getRouterManager","router","getRouter","currentLocation","getCurrentRoute","targetLocation","path","lifecycleManager","beforeEachResult","beforeEach","finalPath","debug","middlewareManager","middlewareContext","from","middlewareResult","execute","allow","redirect","reason","replace","navigate","state","afterEach","duration","getMonitoring","trackRoutePerformance","totalTime","error","Set","goBack","fallback","history","back","warn","goForward","forward"],"mappings":";;;;;;;;;;;;;AAAA;;;CAGC,GAED,SAASA,MAAM,QAAQ,iBAAiB;AAExC,SAASC,yBAAyB,QAAQ,eAAe;AACzD,SAASC,0BAA0B,QAAQ,gBAAgB;AAG3D;;CAEC,GACD,OAAO,MAAMC;IAGX,OAAeC,gBACbC,EAAU,EACVC,KAA+B,EACvB;QACR,MAAMC,OACJ,OAAOC,WAAW,eAAeA,OAAOC,QAAQ,EAAEC,SAC9CF,OAAOC,QAAQ,CAACC,MAAM,GACtB;QAEN,MAAMC,MAAM,IAAIC,IAAIP,IAAIE;QAExB,IAAID,SAASO,OAAOC,IAAI,CAACR,OAAOS,MAAM,GAAG,GAAG;YAC1C,MAAMC,SAAS,IAAIC,gBAAgBN,IAAIO,MAAM;YAC7CL,OAAOM,OAAO,CAACb,OAAOc,OAAO,CAAC,CAAC,CAACC,KAAKC,MAAM;gBACzC,IAAIA,UAAUC,aAAaD,UAAU,MAAM;oBACzCN,OAAOQ,MAAM,CAACH;oBACd;gBACF;gBACAL,OAAOS,GAAG,CAACJ,KAAKK,OAAOJ;YACzB;YACAX,IAAIO,MAAM,GAAGF,OAAOW,QAAQ;QAC9B;QAEA,OAAO,GAAGhB,IAAIiB,QAAQ,GAAGjB,IAAIO,MAAM,GAAGP,IAAIkB,IAAI,EAAE;IAClD;IAEA,aAAqBC,iBACnBzB,EAAU,EACV0B,OAAoC,EACpCC,KAAa,EACbC,OAAoB,EACL;QACf,MAAMC,YAAYC,YAAYC,GAAG;QAEjC,IAAIJ,QAAQ,IAAI,CAACK,aAAa,EAAE;YAC9B,MAAM,IAAIC,MAAM,CAAC,YAAY,EAAE,IAAI,CAACD,aAAa,CAAC,WAAW,CAAC;QAChE;QAEA,MAAME,aAAa,IAAI,CAACnC,eAAe,CAACC,IAAI0B,SAASzB;QACrD,IAAI2B,QAAQO,GAAG,CAACD,aAAa;YAC3B,MAAM,IAAID,MAAM,CAAC,UAAU,EAAEC,YAAY;QAC3C;QACAN,QAAQQ,GAAG,CAACF;QAEZ,MAAMG,gBAAgB,MAAM,MAAM,CAAC,oBAAoBC,IAAI,CAAC,CAACC,IAAMA,EAAEC,gBAAgB;QACrF,MAAMC,SAASJ,cAAcK,SAAS;QAEtC,IAAI,CAACD,QAAQ;YACX,MAAM,IAAIR,MAAM;QAClB;QAEA,WAAW;QACX,MAAMU,kBAAkB,IAAI,CAACC,eAAe;QAE5C,WAAW;QACX,MAAMC,iBAAgC;YACpCC,MAAMZ;YACNjC,OAAOyB,SAASzB;QAClB;QAEA,WAAW;QACX,MAAM8C,mBAAmBnD;QACzB,MAAMoD,mBAAmB,MAAMD,iBAAiBE,UAAU,CACxDJ,gBACAF;QAGF,IAAIO,YAAYhB;QAEhB,8BAA8B;QAC9B,IAAIc,qBAAqB,OAAO;YAC9BrD,OAAOwD,KAAK,CAAC;YACb;QACF;QAEA,8BAA8B;QAC9B,IAAI,OAAOH,qBAAqB,UAAU;YACxCrD,OAAOwD,KAAK,CAAC,CAAC,SAAS,EAAEH,kBAAkB;YAC3CE,YAAY,IAAI,CAACnD,eAAe,CAACiD;QACnC;QAEA,QAAQ;QACR,MAAMI,oBAAoBvD;QAC1B,MAAMwD,oBAA6C;YACjDrD,IAAI;gBACF,GAAG6C,cAAc;gBACjBC,MAAMI;YACR;YACAI,MAAMX;YACNjB;QACF;QAEA,MAAM6B,mBAAmB,MAAMH,kBAAkBI,OAAO,CAACH;QAEzD,YAAY;QACZ,IAAI,CAACE,iBAAiBE,KAAK,EAAE;YAC3B,IAAIF,iBAAiBG,QAAQ,EAAE;gBAC7B/D,OAAOwD,KAAK,CAAC,CAAC,aAAa,EAAEI,iBAAiBG,QAAQ,EAAE;gBACxD,OAAO,IAAI,CAACjC,gBAAgB,CAC1B8B,iBAAiBG,QAAQ,EACzB;oBAAE,GAAGhC,OAAO;oBAAEzB,OAAOiB;gBAAU,GAC/BS,QAAQ,GACRC;YAEJ;YACAjC,OAAOwD,KAAK,CAAC,CAAC,YAAY,EAAEI,iBAAiBI,MAAM,IAAI,QAAQ;YAC/D;QACF;QAEA,OAAO;QACP,IAAI;YACF,IAAIjC,SAASkC,SAAS;gBACpBnB,OAAOoB,QAAQ,CAACX,WAAW;oBAAEU,SAAS;oBAAME,OAAOpC,QAAQoC,KAAK;gBAAC;YACnE,OAAO;gBACLrB,OAAOoB,QAAQ,CAACX,WAAW;oBAAEY,OAAOpC,SAASoC;gBAAM;YACrD;YAEA,kBAAkB;YAClB,MAAMf,iBAAiBgB,SAAS,CAC9B;gBACE,GAAGlB,cAAc;gBACjBC,MAAMI;YACR,GACAP;YAGF,MAAMqB,WAAWlC,YAAYC,GAAG,KAAKF;YACrCQ,cAAc4B,aAAa,GAAGC,qBAAqB,CAAChB,WAAW;gBAC7DiB,WAAWH;YACb;QACF,EAAE,OAAOI,OAAO;YACdzE,OAAOyE,KAAK,CAAC,UAAUA;YACvB,MAAMA;QACR;IACF;IAEA;;;;;GAKC,GACD,aAAaP,SACX7D,EAAU,EACV0B,OAAyB,EACV;QACf,OAAO,IAAI,CAACD,gBAAgB,CAACzB,IAAI0B,SAAS,GAAG,IAAI2C;IACnD;IAEA;;;;GAIC,GACD,OAAOzB,kBAAiC;QACtC,IAAI,OAAOzC,WAAW,aAAa;YACjC,OAAO;gBACL2C,MAAM;gBACN7C,OAAO,CAAC;YACV;QACF;QAEA,6BAA6B;QAC7B,MAAMsB,WAAWpB,OAAOC,QAAQ,CAACmB,QAAQ;QACzC,MAAMV,SAASV,OAAOC,QAAQ,CAACS,MAAM;QACrC,MAAMW,OAAOrB,OAAOC,QAAQ,CAACoB,IAAI;QAEjC,SAAS;QACT,MAAMvB,QAAiC,CAAC;QACxC,IAAIY,QAAQ;YACV,MAAMF,SAAS,IAAIC,gBAAgBC;YACnCF,OAAOI,OAAO,CAAC,CAACE,OAAOD;gBACrBf,KAAK,CAACe,IAAI,GAAGC;YACf;QACF;QAEA,OAAO;YACL6B,MAAMvB,WAAWC;YACjBvB;QACF;IACF;IAEA;;;;GAIC,GACD,aAAaqE,OAAOC,QAAiB,EAAiB;QACpD,IAAIpE,OAAOqE,OAAO,CAAC9D,MAAM,GAAG,GAAG;YAC7BP,OAAOqE,OAAO,CAACC,IAAI;QACrB,OAAO,IAAIF,UAAU;YACnB,MAAM,IAAI,CAACV,QAAQ,CAACU;QACtB,OAAO;YACL5E,OAAO+E,IAAI,CAAC;QACd;IACF;IAEA;;GAEC,GACD,OAAOC,YAAkB;QACvBxE,OAAOqE,OAAO,CAACI,OAAO;IACxB;IAEA;;;;;GAKC,GACD,aAAahB,QACX5D,EAAU,EACV0B,OAA0C,EAC3B;QACf,OAAO,IAAI,CAACmC,QAAQ,CAAC7D,IAAI;YAAE,GAAG0B,OAAO;YAAEkC,SAAS;QAAK;IACvD;AACF;AA1NE,iBADW9D,kBACakC,iBAAgB"}
|
|
@@ -149,8 +149,11 @@ let RouteCache = class RouteCache {
|
|
|
149
149
|
/**
|
|
150
150
|
* 启动定期清理
|
|
151
151
|
*/ startCleanupInterval() {
|
|
152
|
+
if (this.cleanupTimer) {
|
|
153
|
+
clearInterval(this.cleanupTimer);
|
|
154
|
+
}
|
|
152
155
|
// 每 1 分钟清理一次过期缓存
|
|
153
|
-
setInterval(()=>{
|
|
156
|
+
this.cleanupTimer = setInterval(()=>{
|
|
154
157
|
this.cleanup();
|
|
155
158
|
}, 60 * 1000);
|
|
156
159
|
}
|
|
@@ -160,15 +163,18 @@ let RouteCache = class RouteCache {
|
|
|
160
163
|
const key = this.generateKey(routes);
|
|
161
164
|
const item = this.cache.get(key);
|
|
162
165
|
if (!item) {
|
|
166
|
+
this.stats.transformMisses++;
|
|
163
167
|
return null;
|
|
164
168
|
}
|
|
165
169
|
if (this.isExpired(item)) {
|
|
166
170
|
this.cache.delete(key);
|
|
171
|
+
this.stats.transformMisses++;
|
|
167
172
|
return null;
|
|
168
173
|
}
|
|
169
174
|
// 更新访问信息
|
|
170
175
|
item.lastAccessedAt = Date.now();
|
|
171
176
|
item.accessCount++;
|
|
177
|
+
this.stats.transformHits++;
|
|
172
178
|
return item.value;
|
|
173
179
|
}
|
|
174
180
|
/**
|
|
@@ -198,15 +204,18 @@ let RouteCache = class RouteCache {
|
|
|
198
204
|
*/ getMatch(path) {
|
|
199
205
|
const item = this.matchCache.get(path);
|
|
200
206
|
if (!item) {
|
|
207
|
+
this.stats.matchMisses++;
|
|
201
208
|
return undefined;
|
|
202
209
|
}
|
|
203
210
|
if (this.isExpired(item)) {
|
|
204
211
|
this.matchCache.delete(path);
|
|
212
|
+
this.stats.matchMisses++;
|
|
205
213
|
return undefined;
|
|
206
214
|
}
|
|
207
215
|
// 更新访问信息
|
|
208
216
|
item.lastAccessedAt = Date.now();
|
|
209
217
|
item.accessCount++;
|
|
218
|
+
this.stats.matchHits++;
|
|
210
219
|
return item.value;
|
|
211
220
|
}
|
|
212
221
|
/**
|
|
@@ -229,23 +238,28 @@ let RouteCache = class RouteCache {
|
|
|
229
238
|
*/ clear() {
|
|
230
239
|
this.cache.clear();
|
|
231
240
|
this.matchCache.clear();
|
|
241
|
+
this.stats = {
|
|
242
|
+
transformHits: 0,
|
|
243
|
+
transformMisses: 0,
|
|
244
|
+
matchHits: 0,
|
|
245
|
+
matchMisses: 0
|
|
246
|
+
};
|
|
232
247
|
_utils.logger.debug('路由缓存已清空');
|
|
233
248
|
}
|
|
234
249
|
/**
|
|
250
|
+
* 销毁缓存实例并释放资源
|
|
251
|
+
*/ destroy() {
|
|
252
|
+
this.clear();
|
|
253
|
+
if (this.cleanupTimer) {
|
|
254
|
+
clearInterval(this.cleanupTimer);
|
|
255
|
+
this.cleanupTimer = null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
235
259
|
* 获取缓存统计信息
|
|
236
260
|
*/ getStats() {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
// 统计转换结果缓存
|
|
240
|
-
for (const item of this.cache.values()){
|
|
241
|
-
totalHits += item.accessCount;
|
|
242
|
-
totalAccess += item.accessCount;
|
|
243
|
-
}
|
|
244
|
-
// 统计匹配结果缓存
|
|
245
|
-
for (const item of this.matchCache.values()){
|
|
246
|
-
totalHits += item.accessCount;
|
|
247
|
-
totalAccess += item.accessCount;
|
|
248
|
-
}
|
|
261
|
+
const totalHits = this.stats.transformHits + this.stats.matchHits;
|
|
262
|
+
const totalAccess = totalHits + this.stats.transformMisses + this.stats.matchMisses;
|
|
249
263
|
const hitRate = totalAccess > 0 ? totalHits / totalAccess : 0;
|
|
250
264
|
return {
|
|
251
265
|
transformCacheSize: this.cache.size,
|
|
@@ -259,6 +273,13 @@ let RouteCache = class RouteCache {
|
|
|
259
273
|
_define_property(this, "matchCache", new Map());
|
|
260
274
|
_define_property(this, "config", void 0);
|
|
261
275
|
_define_property(this, "persistenceEnabled", false);
|
|
276
|
+
_define_property(this, "cleanupTimer", null);
|
|
277
|
+
_define_property(this, "stats", {
|
|
278
|
+
transformHits: 0,
|
|
279
|
+
transformMisses: 0,
|
|
280
|
+
matchHits: 0,
|
|
281
|
+
matchMisses: 0
|
|
282
|
+
});
|
|
262
283
|
this.config = {
|
|
263
284
|
maxSize: config.maxSize ?? 50,
|
|
264
285
|
ttl: config.ttl ?? 5 * 60 * 1000,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/router/performance/RouteCache.ts"],"sourcesContent":["/**\n * 路由缓存管理器\n * 提供路由转换结果、匹配结果的缓存功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteConfig } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 缓存项接口\n */\ninterface CacheItem<T> {\n /**\n * 缓存值\n */\n value: T;\n /**\n * 过期时间戳\n */\n expiresAt: number;\n /**\n * 创建时间戳\n */\n createdAt: number;\n /**\n * 访问次数\n */\n accessCount: number;\n /**\n * 最后访问时间\n */\n lastAccessedAt: number;\n}\n\n/**\n * LRU 缓存配置\n */\nexport interface RouteCacheConfig {\n /**\n * 最大缓存数量\n * @default 50\n */\n maxSize?: number;\n\n /**\n * 缓存过期时间(毫秒)\n * @default 5 * 60 * 1000 (5分钟)\n */\n ttl?: number;\n\n /**\n * 是否启用持久化缓存(使用 IndexedDB)\n * @default false\n */\n enablePersistence?: boolean;\n\n /**\n * 持久化缓存键前缀\n * @default 'router_cache_'\n */\n persistenceKeyPrefix?: string;\n}\n\n/**\n * 路由缓存管理器\n */\nexport class RouteCache {\n private cache: Map<string, CacheItem<TransformRoutesResult>> = new Map();\n private matchCache: Map<string, CacheItem<RouteConfig | null>> = new Map();\n private config: Required<RouteCacheConfig>;\n private persistenceEnabled: boolean = false;\n\n constructor(config: RouteCacheConfig = {}) {\n this.config = {\n maxSize: config.maxSize ?? 50,\n ttl: config.ttl ?? 5 * 60 * 1000,\n enablePersistence: config.enablePersistence ?? false,\n persistenceKeyPrefix: config.persistenceKeyPrefix ?? 'router_cache_',\n };\n\n // 初始化持久化缓存\n if (this.config.enablePersistence && typeof window !== 'undefined' && 'indexedDB' in window) {\n this.initPersistence();\n }\n\n // 定期清理过期缓存\n this.startCleanupInterval();\n }\n\n /**\n * 初始化持久化缓存\n */\n private async initPersistence(): Promise<void> {\n try {\n // 检查 IndexedDB 是否可用\n if (typeof window !== 'undefined' && 'indexedDB' in window) {\n this.persistenceEnabled = true;\n await this.loadFromPersistence();\n logger.debug('路由缓存持久化已启用');\n }\n } catch (error) {\n logger.warn('路由缓存持久化初始化失败', error);\n this.persistenceEnabled = false;\n }\n }\n\n /**\n * 从持久化存储加载缓存\n */\n private async loadFromPersistence(): Promise<void> {\n try {\n // 这里可以实现从 IndexedDB 加载缓存的逻辑\n // 由于 IndexedDB 操作较复杂,这里先留空\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('从持久化存储加载缓存失败', error);\n }\n }\n\n /**\n * 保存到持久化存储\n */\n private async saveToPersistence(_key: string, _value: TransformRoutesResult): Promise<void> {\n if (!this.persistenceEnabled) {\n return;\n }\n\n try {\n // 这里可以实现保存到 IndexedDB 的逻辑\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('保存到持久化存储失败', error);\n }\n }\n\n /**\n * 生成缓存键\n */\n private generateKey(routes: RouteConfig[] | (() => Promise<RouteConfig[]>)): string {\n if (typeof routes === 'function') {\n // 对于函数,使用函数名或随机 ID\n return `fn_${routes.name || Math.random().toString(36).substring(7)}`;\n }\n\n // 对于数组,使用 JSON.stringify 生成键(注意:这可能会很慢)\n // 实际使用中可以考虑使用路由配置的哈希值\n try {\n const routesStr = JSON.stringify(routes, (_key, value) => {\n // 过滤掉函数,避免序列化问题\n if (typeof value === 'function') {\n return '[Function]';\n }\n return value;\n });\n return `routes_${this.hashString(routesStr)}`;\n } catch (error) {\n // 如果序列化失败,使用随机键\n return `routes_${Math.random().toString(36).substring(7)}`;\n }\n }\n\n /**\n * 字符串哈希函数(简单实现)\n */\n private hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // 转换为 32 位整数\n }\n return Math.abs(hash).toString(36);\n }\n\n /**\n * 检查缓存项是否过期\n */\n private isExpired(item: CacheItem<unknown>): boolean {\n return Date.now() > item.expiresAt;\n }\n\n /**\n * 清理过期缓存\n */\n private cleanup(): void {\n\n // 清理转换结果缓存\n for (const [key, item] of this.cache.entries()) {\n if (this.isExpired(item)) {\n this.cache.delete(key);\n }\n }\n\n // 清理匹配结果缓存\n for (const [key, item] of this.matchCache.entries()) {\n if (this.isExpired(item)) {\n this.matchCache.delete(key);\n }\n }\n\n // 如果缓存超过最大大小,删除最久未访问的项(LRU)\n this.evictLRU();\n }\n\n /**\n * LRU 淘汰策略\n */\n private evictLRU(): void {\n // 清理转换结果缓存\n if (this.cache.size > this.config.maxSize) {\n const sorted = Array.from(this.cache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.cache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.cache.delete(key));\n }\n\n // 清理匹配结果缓存\n if (this.matchCache.size > this.config.maxSize) {\n const sorted = Array.from(this.matchCache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.matchCache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.matchCache.delete(key));\n }\n }\n\n /**\n * 启动定期清理\n */\n private startCleanupInterval(): void {\n // 每 1 分钟清理一次过期缓存\n setInterval(() => {\n this.cleanup();\n }, 60 * 1000);\n }\n\n /**\n * 获取转换结果缓存\n */\n get(routes: RouteConfig[] | (() => Promise<RouteConfig[]>)): TransformRoutesResult | null {\n const key = this.generateKey(routes);\n const item = this.cache.get(key);\n\n if (!item) {\n return null;\n }\n\n if (this.isExpired(item)) {\n this.cache.delete(key);\n return null;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n\n return item.value;\n }\n\n /**\n * 设置转换结果缓存\n */\n set(\n routes: RouteConfig[] | (() => Promise<RouteConfig[]>),\n value: TransformRoutesResult\n ): void {\n const key = this.generateKey(routes);\n const now = Date.now();\n\n const item: CacheItem<TransformRoutesResult> = {\n value,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.cache.set(key, item);\n\n // 保存到持久化存储\n if (this.persistenceEnabled) {\n this.saveToPersistence(key, value).catch((error) => {\n logger.warn('保存缓存到持久化存储失败', error);\n });\n }\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 获取路由匹配缓存\n */\n getMatch(path: string): RouteConfig | null | undefined {\n const item = this.matchCache.get(path);\n\n if (!item) {\n return undefined;\n }\n\n if (this.isExpired(item)) {\n this.matchCache.delete(path);\n return undefined;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n\n return item.value;\n }\n\n /**\n * 设置路由匹配缓存\n */\n setMatch(path: string, route: RouteConfig | null): void {\n const now = Date.now();\n\n const item: CacheItem<RouteConfig | null> = {\n value: route,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.matchCache.set(path, item);\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 清空所有缓存\n */\n clear(): void {\n this.cache.clear();\n this.matchCache.clear();\n logger.debug('路由缓存已清空');\n }\n\n /**\n * 获取缓存统计信息\n */\n getStats(): {\n transformCacheSize: number;\n matchCacheSize: number;\n totalSize: number;\n hitRate: number;\n } {\n let totalHits = 0;\n let totalAccess = 0;\n\n // 统计转换结果缓存\n for (const item of this.cache.values()) {\n totalHits += item.accessCount;\n totalAccess += item.accessCount;\n }\n\n // 统计匹配结果缓存\n for (const item of this.matchCache.values()) {\n totalHits += item.accessCount;\n totalAccess += item.accessCount;\n }\n\n const hitRate = totalAccess > 0 ? totalHits / totalAccess : 0;\n\n return {\n transformCacheSize: this.cache.size,\n matchCacheSize: this.matchCache.size,\n totalSize: this.cache.size + this.matchCache.size,\n hitRate,\n };\n }\n}\n\n/**\n * 获取路由缓存管理器单例\n */\nlet routeCacheInstance: RouteCache | null = null;\n\nexport function getRouteCache(config?: RouteCacheConfig): RouteCache {\n if (!routeCacheInstance) {\n routeCacheInstance = new RouteCache(config);\n }\n return routeCacheInstance;\n}\n"],"names":["RouteCache","getRouteCache","initPersistence","window","persistenceEnabled","loadFromPersistence","logger","debug","error","warn","saveToPersistence","_key","_value","generateKey","routes","name","Math","random","toString","substring","routesStr","JSON","stringify","value","hashString","str","hash","i","length","char","charCodeAt","abs","isExpired","item","Date","now","expiresAt","cleanup","key","cache","entries","delete","matchCache","evictLRU","size","config","maxSize","sorted","Array","from","sort","a","b","lastAccessedAt","toDelete","slice","forEach","startCleanupInterval","setInterval","get","accessCount","set","ttl","createdAt","catch","getMatch","path","undefined","setMatch","route","clear","getStats","totalHits","totalAccess","values","hitRate","transformCacheSize","matchCacheSize","totalSize","Map","enablePersistence","persistenceKeyPrefix","routeCacheInstance"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/router/performance/RouteCache.ts"],"sourcesContent":["/**\n * 路由缓存管理器\n * 提供路由转换结果、匹配结果的缓存功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteConfig } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 缓存项接口\n */\ninterface CacheItem<T> {\n /**\n * 缓存值\n */\n value: T;\n /**\n * 过期时间戳\n */\n expiresAt: number;\n /**\n * 创建时间戳\n */\n createdAt: number;\n /**\n * 访问次数\n */\n accessCount: number;\n /**\n * 最后访问时间\n */\n lastAccessedAt: number;\n}\n\n/**\n * LRU 缓存配置\n */\nexport interface RouteCacheConfig {\n /**\n * 最大缓存数量\n * @default 50\n */\n maxSize?: number;\n\n /**\n * 缓存过期时间(毫秒)\n * @default 5 * 60 * 1000 (5分钟)\n */\n ttl?: number;\n\n /**\n * 是否启用持久化缓存(使用 IndexedDB)\n * @default false\n */\n enablePersistence?: boolean;\n\n /**\n * 持久化缓存键前缀\n * @default 'router_cache_'\n */\n persistenceKeyPrefix?: string;\n}\n\n/**\n * 路由缓存管理器\n */\nexport class RouteCache {\n private cache: Map<string, CacheItem<TransformRoutesResult>> = new Map();\n private matchCache: Map<string, CacheItem<RouteConfig | null>> = new Map();\n private config: Required<RouteCacheConfig>;\n private persistenceEnabled: boolean = false;\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\n private stats = {\n transformHits: 0,\n transformMisses: 0,\n matchHits: 0,\n matchMisses: 0,\n };\n\n constructor(config: RouteCacheConfig = {}) {\n this.config = {\n maxSize: config.maxSize ?? 50,\n ttl: config.ttl ?? 5 * 60 * 1000,\n enablePersistence: config.enablePersistence ?? false,\n persistenceKeyPrefix: config.persistenceKeyPrefix ?? 'router_cache_',\n };\n\n // 初始化持久化缓存\n if (this.config.enablePersistence && typeof window !== 'undefined' && 'indexedDB' in window) {\n this.initPersistence();\n }\n\n // 定期清理过期缓存\n this.startCleanupInterval();\n }\n\n /**\n * 初始化持久化缓存\n */\n private async initPersistence(): Promise<void> {\n try {\n // 检查 IndexedDB 是否可用\n if (typeof window !== 'undefined' && 'indexedDB' in window) {\n this.persistenceEnabled = true;\n await this.loadFromPersistence();\n logger.debug('路由缓存持久化已启用');\n }\n } catch (error) {\n logger.warn('路由缓存持久化初始化失败', error);\n this.persistenceEnabled = false;\n }\n }\n\n /**\n * 从持久化存储加载缓存\n */\n private async loadFromPersistence(): Promise<void> {\n try {\n // 这里可以实现从 IndexedDB 加载缓存的逻辑\n // 由于 IndexedDB 操作较复杂,这里先留空\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('从持久化存储加载缓存失败', error);\n }\n }\n\n /**\n * 保存到持久化存储\n */\n private async saveToPersistence(_key: string, _value: TransformRoutesResult): Promise<void> {\n if (!this.persistenceEnabled) {\n return;\n }\n\n try {\n // 这里可以实现保存到 IndexedDB 的逻辑\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('保存到持久化存储失败', error);\n }\n }\n\n /**\n * 生成缓存键\n */\n private generateKey(routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>)): string {\n if (typeof routes === 'function') {\n // 对于函数,使用函数名或随机 ID\n return `fn_${routes.name || Math.random().toString(36).substring(7)}`;\n }\n\n // 对于数组,使用 JSON.stringify 生成键(注意:这可能会很慢)\n // 实际使用中可以考虑使用路由配置的哈希值\n try {\n const routesStr = JSON.stringify(routes, (_key, value) => {\n // 过滤掉函数,避免序列化问题\n if (typeof value === 'function') {\n return '[Function]';\n }\n return value;\n });\n return `routes_${this.hashString(routesStr)}`;\n } catch (error) {\n // 如果序列化失败,使用随机键\n return `routes_${Math.random().toString(36).substring(7)}`;\n }\n }\n\n /**\n * 字符串哈希函数(简单实现)\n */\n private hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // 转换为 32 位整数\n }\n return Math.abs(hash).toString(36);\n }\n\n /**\n * 检查缓存项是否过期\n */\n private isExpired(item: CacheItem<unknown>): boolean {\n return Date.now() > item.expiresAt;\n }\n\n /**\n * 清理过期缓存\n */\n private cleanup(): void {\n\n // 清理转换结果缓存\n for (const [key, item] of this.cache.entries()) {\n if (this.isExpired(item)) {\n this.cache.delete(key);\n }\n }\n\n // 清理匹配结果缓存\n for (const [key, item] of this.matchCache.entries()) {\n if (this.isExpired(item)) {\n this.matchCache.delete(key);\n }\n }\n\n // 如果缓存超过最大大小,删除最久未访问的项(LRU)\n this.evictLRU();\n }\n\n /**\n * LRU 淘汰策略\n */\n private evictLRU(): void {\n // 清理转换结果缓存\n if (this.cache.size > this.config.maxSize) {\n const sorted = Array.from(this.cache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.cache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.cache.delete(key));\n }\n\n // 清理匹配结果缓存\n if (this.matchCache.size > this.config.maxSize) {\n const sorted = Array.from(this.matchCache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.matchCache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.matchCache.delete(key));\n }\n }\n\n /**\n * 启动定期清理\n */\n private startCleanupInterval(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n }\n\n // 每 1 分钟清理一次过期缓存\n this.cleanupTimer = setInterval(() => {\n this.cleanup();\n }, 60 * 1000);\n }\n\n /**\n * 获取转换结果缓存\n */\n get(routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>)): TransformRoutesResult | null {\n const key = this.generateKey(routes);\n const item = this.cache.get(key);\n\n if (!item) {\n this.stats.transformMisses++;\n return null;\n }\n\n if (this.isExpired(item)) {\n this.cache.delete(key);\n this.stats.transformMisses++;\n return null;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n this.stats.transformHits++;\n\n return item.value;\n }\n\n /**\n * 设置转换结果缓存\n */\n set(\n routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>),\n value: TransformRoutesResult\n ): void {\n const key = this.generateKey(routes);\n const now = Date.now();\n\n const item: CacheItem<TransformRoutesResult> = {\n value,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.cache.set(key, item);\n\n // 保存到持久化存储\n if (this.persistenceEnabled) {\n this.saveToPersistence(key, value).catch((error) => {\n logger.warn('保存缓存到持久化存储失败', error);\n });\n }\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 获取路由匹配缓存\n */\n getMatch(path: string): RouteConfig | null | undefined {\n const item = this.matchCache.get(path);\n\n if (!item) {\n this.stats.matchMisses++;\n return undefined;\n }\n\n if (this.isExpired(item)) {\n this.matchCache.delete(path);\n this.stats.matchMisses++;\n return undefined;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n this.stats.matchHits++;\n\n return item.value;\n }\n\n /**\n * 设置路由匹配缓存\n */\n setMatch(path: string, route: RouteConfig | null): void {\n const now = Date.now();\n\n const item: CacheItem<RouteConfig | null> = {\n value: route,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.matchCache.set(path, item);\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 清空所有缓存\n */\n clear(): void {\n this.cache.clear();\n this.matchCache.clear();\n this.stats = {\n transformHits: 0,\n transformMisses: 0,\n matchHits: 0,\n matchMisses: 0,\n };\n logger.debug('路由缓存已清空');\n }\n\n /**\n * 销毁缓存实例并释放资源\n */\n destroy(): void {\n this.clear();\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n getStats(): {\n transformCacheSize: number;\n matchCacheSize: number;\n totalSize: number;\n hitRate: number;\n } {\n const totalHits = this.stats.transformHits + this.stats.matchHits;\n const totalAccess =\n totalHits +\n this.stats.transformMisses +\n this.stats.matchMisses;\n\n const hitRate = totalAccess > 0 ? totalHits / totalAccess : 0;\n\n return {\n transformCacheSize: this.cache.size,\n matchCacheSize: this.matchCache.size,\n totalSize: this.cache.size + this.matchCache.size,\n hitRate,\n };\n }\n}\n\n/**\n * 获取路由缓存管理器单例\n */\nlet routeCacheInstance: RouteCache | null = null;\n\nexport function getRouteCache(config?: RouteCacheConfig): RouteCache {\n if (!routeCacheInstance) {\n routeCacheInstance = new RouteCache(config);\n }\n return routeCacheInstance;\n}\n"],"names":["RouteCache","getRouteCache","initPersistence","window","persistenceEnabled","loadFromPersistence","logger","debug","error","warn","saveToPersistence","_key","_value","generateKey","routes","name","Math","random","toString","substring","routesStr","JSON","stringify","value","hashString","str","hash","i","length","char","charCodeAt","abs","isExpired","item","Date","now","expiresAt","cleanup","key","cache","entries","delete","matchCache","evictLRU","size","config","maxSize","sorted","Array","from","sort","a","b","lastAccessedAt","toDelete","slice","forEach","startCleanupInterval","cleanupTimer","clearInterval","setInterval","get","stats","transformMisses","accessCount","transformHits","set","ttl","createdAt","catch","getMatch","path","matchMisses","undefined","matchHits","setMatch","route","clear","destroy","getStats","totalHits","totalAccess","hitRate","transformCacheSize","matchCacheSize","totalSize","Map","enablePersistence","persistenceKeyPrefix","routeCacheInstance"],"mappings":"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"}
|
|
@@ -37,6 +37,8 @@ export declare class RouteCache {
|
|
|
37
37
|
private matchCache;
|
|
38
38
|
private config;
|
|
39
39
|
private persistenceEnabled;
|
|
40
|
+
private cleanupTimer;
|
|
41
|
+
private stats;
|
|
40
42
|
constructor(config?: RouteCacheConfig);
|
|
41
43
|
/**
|
|
42
44
|
* 初始化持久化缓存
|
|
@@ -77,11 +79,11 @@ export declare class RouteCache {
|
|
|
77
79
|
/**
|
|
78
80
|
* 获取转换结果缓存
|
|
79
81
|
*/
|
|
80
|
-
get(routes: RouteConfig[] | (() => Promise<RouteConfig[]>)): TransformRoutesResult | null;
|
|
82
|
+
get(routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>)): TransformRoutesResult | null;
|
|
81
83
|
/**
|
|
82
84
|
* 设置转换结果缓存
|
|
83
85
|
*/
|
|
84
|
-
set(routes: RouteConfig[] | (() => Promise<RouteConfig[]>), value: TransformRoutesResult): void;
|
|
86
|
+
set(routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>), value: TransformRoutesResult): void;
|
|
85
87
|
/**
|
|
86
88
|
* 获取路由匹配缓存
|
|
87
89
|
*/
|
|
@@ -94,6 +96,10 @@ export declare class RouteCache {
|
|
|
94
96
|
* 清空所有缓存
|
|
95
97
|
*/
|
|
96
98
|
clear(): void;
|
|
99
|
+
/**
|
|
100
|
+
* 销毁缓存实例并释放资源
|
|
101
|
+
*/
|
|
102
|
+
destroy(): void;
|
|
97
103
|
/**
|
|
98
104
|
* 获取缓存统计信息
|
|
99
105
|
*/
|
|
@@ -133,8 +133,11 @@ function _define_property(obj, key, value) {
|
|
|
133
133
|
/**
|
|
134
134
|
* 启动定期清理
|
|
135
135
|
*/ startCleanupInterval() {
|
|
136
|
+
if (this.cleanupTimer) {
|
|
137
|
+
clearInterval(this.cleanupTimer);
|
|
138
|
+
}
|
|
136
139
|
// 每 1 分钟清理一次过期缓存
|
|
137
|
-
setInterval(()=>{
|
|
140
|
+
this.cleanupTimer = setInterval(()=>{
|
|
138
141
|
this.cleanup();
|
|
139
142
|
}, 60 * 1000);
|
|
140
143
|
}
|
|
@@ -144,15 +147,18 @@ function _define_property(obj, key, value) {
|
|
|
144
147
|
const key = this.generateKey(routes);
|
|
145
148
|
const item = this.cache.get(key);
|
|
146
149
|
if (!item) {
|
|
150
|
+
this.stats.transformMisses++;
|
|
147
151
|
return null;
|
|
148
152
|
}
|
|
149
153
|
if (this.isExpired(item)) {
|
|
150
154
|
this.cache.delete(key);
|
|
155
|
+
this.stats.transformMisses++;
|
|
151
156
|
return null;
|
|
152
157
|
}
|
|
153
158
|
// 更新访问信息
|
|
154
159
|
item.lastAccessedAt = Date.now();
|
|
155
160
|
item.accessCount++;
|
|
161
|
+
this.stats.transformHits++;
|
|
156
162
|
return item.value;
|
|
157
163
|
}
|
|
158
164
|
/**
|
|
@@ -182,15 +188,18 @@ function _define_property(obj, key, value) {
|
|
|
182
188
|
*/ getMatch(path) {
|
|
183
189
|
const item = this.matchCache.get(path);
|
|
184
190
|
if (!item) {
|
|
191
|
+
this.stats.matchMisses++;
|
|
185
192
|
return undefined;
|
|
186
193
|
}
|
|
187
194
|
if (this.isExpired(item)) {
|
|
188
195
|
this.matchCache.delete(path);
|
|
196
|
+
this.stats.matchMisses++;
|
|
189
197
|
return undefined;
|
|
190
198
|
}
|
|
191
199
|
// 更新访问信息
|
|
192
200
|
item.lastAccessedAt = Date.now();
|
|
193
201
|
item.accessCount++;
|
|
202
|
+
this.stats.matchHits++;
|
|
194
203
|
return item.value;
|
|
195
204
|
}
|
|
196
205
|
/**
|
|
@@ -213,23 +222,28 @@ function _define_property(obj, key, value) {
|
|
|
213
222
|
*/ clear() {
|
|
214
223
|
this.cache.clear();
|
|
215
224
|
this.matchCache.clear();
|
|
225
|
+
this.stats = {
|
|
226
|
+
transformHits: 0,
|
|
227
|
+
transformMisses: 0,
|
|
228
|
+
matchHits: 0,
|
|
229
|
+
matchMisses: 0
|
|
230
|
+
};
|
|
216
231
|
logger.debug('路由缓存已清空');
|
|
217
232
|
}
|
|
218
233
|
/**
|
|
234
|
+
* 销毁缓存实例并释放资源
|
|
235
|
+
*/ destroy() {
|
|
236
|
+
this.clear();
|
|
237
|
+
if (this.cleanupTimer) {
|
|
238
|
+
clearInterval(this.cleanupTimer);
|
|
239
|
+
this.cleanupTimer = null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
219
243
|
* 获取缓存统计信息
|
|
220
244
|
*/ getStats() {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
// 统计转换结果缓存
|
|
224
|
-
for (const item of this.cache.values()){
|
|
225
|
-
totalHits += item.accessCount;
|
|
226
|
-
totalAccess += item.accessCount;
|
|
227
|
-
}
|
|
228
|
-
// 统计匹配结果缓存
|
|
229
|
-
for (const item of this.matchCache.values()){
|
|
230
|
-
totalHits += item.accessCount;
|
|
231
|
-
totalAccess += item.accessCount;
|
|
232
|
-
}
|
|
245
|
+
const totalHits = this.stats.transformHits + this.stats.matchHits;
|
|
246
|
+
const totalAccess = totalHits + this.stats.transformMisses + this.stats.matchMisses;
|
|
233
247
|
const hitRate = totalAccess > 0 ? totalHits / totalAccess : 0;
|
|
234
248
|
return {
|
|
235
249
|
transformCacheSize: this.cache.size,
|
|
@@ -243,6 +257,13 @@ function _define_property(obj, key, value) {
|
|
|
243
257
|
_define_property(this, "matchCache", new Map());
|
|
244
258
|
_define_property(this, "config", void 0);
|
|
245
259
|
_define_property(this, "persistenceEnabled", false);
|
|
260
|
+
_define_property(this, "cleanupTimer", null);
|
|
261
|
+
_define_property(this, "stats", {
|
|
262
|
+
transformHits: 0,
|
|
263
|
+
transformMisses: 0,
|
|
264
|
+
matchHits: 0,
|
|
265
|
+
matchMisses: 0
|
|
266
|
+
});
|
|
246
267
|
this.config = {
|
|
247
268
|
maxSize: config.maxSize ?? 50,
|
|
248
269
|
ttl: config.ttl ?? 5 * 60 * 1000,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/router/performance/RouteCache.ts"],"sourcesContent":["/**\n * 路由缓存管理器\n * 提供路由转换结果、匹配结果的缓存功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteConfig } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 缓存项接口\n */\ninterface CacheItem<T> {\n /**\n * 缓存值\n */\n value: T;\n /**\n * 过期时间戳\n */\n expiresAt: number;\n /**\n * 创建时间戳\n */\n createdAt: number;\n /**\n * 访问次数\n */\n accessCount: number;\n /**\n * 最后访问时间\n */\n lastAccessedAt: number;\n}\n\n/**\n * LRU 缓存配置\n */\nexport interface RouteCacheConfig {\n /**\n * 最大缓存数量\n * @default 50\n */\n maxSize?: number;\n\n /**\n * 缓存过期时间(毫秒)\n * @default 5 * 60 * 1000 (5分钟)\n */\n ttl?: number;\n\n /**\n * 是否启用持久化缓存(使用 IndexedDB)\n * @default false\n */\n enablePersistence?: boolean;\n\n /**\n * 持久化缓存键前缀\n * @default 'router_cache_'\n */\n persistenceKeyPrefix?: string;\n}\n\n/**\n * 路由缓存管理器\n */\nexport class RouteCache {\n private cache: Map<string, CacheItem<TransformRoutesResult>> = new Map();\n private matchCache: Map<string, CacheItem<RouteConfig | null>> = new Map();\n private config: Required<RouteCacheConfig>;\n private persistenceEnabled: boolean = false;\n\n constructor(config: RouteCacheConfig = {}) {\n this.config = {\n maxSize: config.maxSize ?? 50,\n ttl: config.ttl ?? 5 * 60 * 1000,\n enablePersistence: config.enablePersistence ?? false,\n persistenceKeyPrefix: config.persistenceKeyPrefix ?? 'router_cache_',\n };\n\n // 初始化持久化缓存\n if (this.config.enablePersistence && typeof window !== 'undefined' && 'indexedDB' in window) {\n this.initPersistence();\n }\n\n // 定期清理过期缓存\n this.startCleanupInterval();\n }\n\n /**\n * 初始化持久化缓存\n */\n private async initPersistence(): Promise<void> {\n try {\n // 检查 IndexedDB 是否可用\n if (typeof window !== 'undefined' && 'indexedDB' in window) {\n this.persistenceEnabled = true;\n await this.loadFromPersistence();\n logger.debug('路由缓存持久化已启用');\n }\n } catch (error) {\n logger.warn('路由缓存持久化初始化失败', error);\n this.persistenceEnabled = false;\n }\n }\n\n /**\n * 从持久化存储加载缓存\n */\n private async loadFromPersistence(): Promise<void> {\n try {\n // 这里可以实现从 IndexedDB 加载缓存的逻辑\n // 由于 IndexedDB 操作较复杂,这里先留空\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('从持久化存储加载缓存失败', error);\n }\n }\n\n /**\n * 保存到持久化存储\n */\n private async saveToPersistence(_key: string, _value: TransformRoutesResult): Promise<void> {\n if (!this.persistenceEnabled) {\n return;\n }\n\n try {\n // 这里可以实现保存到 IndexedDB 的逻辑\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('保存到持久化存储失败', error);\n }\n }\n\n /**\n * 生成缓存键\n */\n private generateKey(routes: RouteConfig[] | (() => Promise<RouteConfig[]>)): string {\n if (typeof routes === 'function') {\n // 对于函数,使用函数名或随机 ID\n return `fn_${routes.name || Math.random().toString(36).substring(7)}`;\n }\n\n // 对于数组,使用 JSON.stringify 生成键(注意:这可能会很慢)\n // 实际使用中可以考虑使用路由配置的哈希值\n try {\n const routesStr = JSON.stringify(routes, (_key, value) => {\n // 过滤掉函数,避免序列化问题\n if (typeof value === 'function') {\n return '[Function]';\n }\n return value;\n });\n return `routes_${this.hashString(routesStr)}`;\n } catch (error) {\n // 如果序列化失败,使用随机键\n return `routes_${Math.random().toString(36).substring(7)}`;\n }\n }\n\n /**\n * 字符串哈希函数(简单实现)\n */\n private hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // 转换为 32 位整数\n }\n return Math.abs(hash).toString(36);\n }\n\n /**\n * 检查缓存项是否过期\n */\n private isExpired(item: CacheItem<unknown>): boolean {\n return Date.now() > item.expiresAt;\n }\n\n /**\n * 清理过期缓存\n */\n private cleanup(): void {\n\n // 清理转换结果缓存\n for (const [key, item] of this.cache.entries()) {\n if (this.isExpired(item)) {\n this.cache.delete(key);\n }\n }\n\n // 清理匹配结果缓存\n for (const [key, item] of this.matchCache.entries()) {\n if (this.isExpired(item)) {\n this.matchCache.delete(key);\n }\n }\n\n // 如果缓存超过最大大小,删除最久未访问的项(LRU)\n this.evictLRU();\n }\n\n /**\n * LRU 淘汰策略\n */\n private evictLRU(): void {\n // 清理转换结果缓存\n if (this.cache.size > this.config.maxSize) {\n const sorted = Array.from(this.cache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.cache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.cache.delete(key));\n }\n\n // 清理匹配结果缓存\n if (this.matchCache.size > this.config.maxSize) {\n const sorted = Array.from(this.matchCache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.matchCache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.matchCache.delete(key));\n }\n }\n\n /**\n * 启动定期清理\n */\n private startCleanupInterval(): void {\n // 每 1 分钟清理一次过期缓存\n setInterval(() => {\n this.cleanup();\n }, 60 * 1000);\n }\n\n /**\n * 获取转换结果缓存\n */\n get(routes: RouteConfig[] | (() => Promise<RouteConfig[]>)): TransformRoutesResult | null {\n const key = this.generateKey(routes);\n const item = this.cache.get(key);\n\n if (!item) {\n return null;\n }\n\n if (this.isExpired(item)) {\n this.cache.delete(key);\n return null;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n\n return item.value;\n }\n\n /**\n * 设置转换结果缓存\n */\n set(\n routes: RouteConfig[] | (() => Promise<RouteConfig[]>),\n value: TransformRoutesResult\n ): void {\n const key = this.generateKey(routes);\n const now = Date.now();\n\n const item: CacheItem<TransformRoutesResult> = {\n value,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.cache.set(key, item);\n\n // 保存到持久化存储\n if (this.persistenceEnabled) {\n this.saveToPersistence(key, value).catch((error) => {\n logger.warn('保存缓存到持久化存储失败', error);\n });\n }\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 获取路由匹配缓存\n */\n getMatch(path: string): RouteConfig | null | undefined {\n const item = this.matchCache.get(path);\n\n if (!item) {\n return undefined;\n }\n\n if (this.isExpired(item)) {\n this.matchCache.delete(path);\n return undefined;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n\n return item.value;\n }\n\n /**\n * 设置路由匹配缓存\n */\n setMatch(path: string, route: RouteConfig | null): void {\n const now = Date.now();\n\n const item: CacheItem<RouteConfig | null> = {\n value: route,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.matchCache.set(path, item);\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 清空所有缓存\n */\n clear(): void {\n this.cache.clear();\n this.matchCache.clear();\n logger.debug('路由缓存已清空');\n }\n\n /**\n * 获取缓存统计信息\n */\n getStats(): {\n transformCacheSize: number;\n matchCacheSize: number;\n totalSize: number;\n hitRate: number;\n } {\n let totalHits = 0;\n let totalAccess = 0;\n\n // 统计转换结果缓存\n for (const item of this.cache.values()) {\n totalHits += item.accessCount;\n totalAccess += item.accessCount;\n }\n\n // 统计匹配结果缓存\n for (const item of this.matchCache.values()) {\n totalHits += item.accessCount;\n totalAccess += item.accessCount;\n }\n\n const hitRate = totalAccess > 0 ? totalHits / totalAccess : 0;\n\n return {\n transformCacheSize: this.cache.size,\n matchCacheSize: this.matchCache.size,\n totalSize: this.cache.size + this.matchCache.size,\n hitRate,\n };\n }\n}\n\n/**\n * 获取路由缓存管理器单例\n */\nlet routeCacheInstance: RouteCache | null = null;\n\nexport function getRouteCache(config?: RouteCacheConfig): RouteCache {\n if (!routeCacheInstance) {\n routeCacheInstance = new RouteCache(config);\n }\n return routeCacheInstance;\n}\n"],"names":["logger","RouteCache","initPersistence","window","persistenceEnabled","loadFromPersistence","debug","error","warn","saveToPersistence","_key","_value","generateKey","routes","name","Math","random","toString","substring","routesStr","JSON","stringify","value","hashString","str","hash","i","length","char","charCodeAt","abs","isExpired","item","Date","now","expiresAt","cleanup","key","cache","entries","delete","matchCache","evictLRU","size","config","maxSize","sorted","Array","from","sort","a","b","lastAccessedAt","toDelete","slice","forEach","startCleanupInterval","setInterval","get","accessCount","set","ttl","createdAt","catch","getMatch","path","undefined","setMatch","route","clear","getStats","totalHits","totalAccess","values","hitRate","transformCacheSize","matchCacheSize","totalSize","Map","enablePersistence","persistenceKeyPrefix","routeCacheInstance","getRouteCache"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/router/performance/RouteCache.ts"],"sourcesContent":["/**\n * 路由缓存管理器\n * 提供路由转换结果、匹配结果的缓存功能\n */\n\nimport { logger } from '../../../utils';\nimport type { RouteConfig } from '../types';\nimport type { TransformRoutesResult } from '../utils/transform';\n\n/**\n * 缓存项接口\n */\ninterface CacheItem<T> {\n /**\n * 缓存值\n */\n value: T;\n /**\n * 过期时间戳\n */\n expiresAt: number;\n /**\n * 创建时间戳\n */\n createdAt: number;\n /**\n * 访问次数\n */\n accessCount: number;\n /**\n * 最后访问时间\n */\n lastAccessedAt: number;\n}\n\n/**\n * LRU 缓存配置\n */\nexport interface RouteCacheConfig {\n /**\n * 最大缓存数量\n * @default 50\n */\n maxSize?: number;\n\n /**\n * 缓存过期时间(毫秒)\n * @default 5 * 60 * 1000 (5分钟)\n */\n ttl?: number;\n\n /**\n * 是否启用持久化缓存(使用 IndexedDB)\n * @default false\n */\n enablePersistence?: boolean;\n\n /**\n * 持久化缓存键前缀\n * @default 'router_cache_'\n */\n persistenceKeyPrefix?: string;\n}\n\n/**\n * 路由缓存管理器\n */\nexport class RouteCache {\n private cache: Map<string, CacheItem<TransformRoutesResult>> = new Map();\n private matchCache: Map<string, CacheItem<RouteConfig | null>> = new Map();\n private config: Required<RouteCacheConfig>;\n private persistenceEnabled: boolean = false;\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\n private stats = {\n transformHits: 0,\n transformMisses: 0,\n matchHits: 0,\n matchMisses: 0,\n };\n\n constructor(config: RouteCacheConfig = {}) {\n this.config = {\n maxSize: config.maxSize ?? 50,\n ttl: config.ttl ?? 5 * 60 * 1000,\n enablePersistence: config.enablePersistence ?? false,\n persistenceKeyPrefix: config.persistenceKeyPrefix ?? 'router_cache_',\n };\n\n // 初始化持久化缓存\n if (this.config.enablePersistence && typeof window !== 'undefined' && 'indexedDB' in window) {\n this.initPersistence();\n }\n\n // 定期清理过期缓存\n this.startCleanupInterval();\n }\n\n /**\n * 初始化持久化缓存\n */\n private async initPersistence(): Promise<void> {\n try {\n // 检查 IndexedDB 是否可用\n if (typeof window !== 'undefined' && 'indexedDB' in window) {\n this.persistenceEnabled = true;\n await this.loadFromPersistence();\n logger.debug('路由缓存持久化已启用');\n }\n } catch (error) {\n logger.warn('路由缓存持久化初始化失败', error);\n this.persistenceEnabled = false;\n }\n }\n\n /**\n * 从持久化存储加载缓存\n */\n private async loadFromPersistence(): Promise<void> {\n try {\n // 这里可以实现从 IndexedDB 加载缓存的逻辑\n // 由于 IndexedDB 操作较复杂,这里先留空\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('从持久化存储加载缓存失败', error);\n }\n }\n\n /**\n * 保存到持久化存储\n */\n private async saveToPersistence(_key: string, _value: TransformRoutesResult): Promise<void> {\n if (!this.persistenceEnabled) {\n return;\n }\n\n try {\n // 这里可以实现保存到 IndexedDB 的逻辑\n // 实际实现可以使用 idb 库或原生 IndexedDB API\n } catch (error) {\n logger.warn('保存到持久化存储失败', error);\n }\n }\n\n /**\n * 生成缓存键\n */\n private generateKey(routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>)): string {\n if (typeof routes === 'function') {\n // 对于函数,使用函数名或随机 ID\n return `fn_${routes.name || Math.random().toString(36).substring(7)}`;\n }\n\n // 对于数组,使用 JSON.stringify 生成键(注意:这可能会很慢)\n // 实际使用中可以考虑使用路由配置的哈希值\n try {\n const routesStr = JSON.stringify(routes, (_key, value) => {\n // 过滤掉函数,避免序列化问题\n if (typeof value === 'function') {\n return '[Function]';\n }\n return value;\n });\n return `routes_${this.hashString(routesStr)}`;\n } catch (error) {\n // 如果序列化失败,使用随机键\n return `routes_${Math.random().toString(36).substring(7)}`;\n }\n }\n\n /**\n * 字符串哈希函数(简单实现)\n */\n private hashString(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // 转换为 32 位整数\n }\n return Math.abs(hash).toString(36);\n }\n\n /**\n * 检查缓存项是否过期\n */\n private isExpired(item: CacheItem<unknown>): boolean {\n return Date.now() > item.expiresAt;\n }\n\n /**\n * 清理过期缓存\n */\n private cleanup(): void {\n\n // 清理转换结果缓存\n for (const [key, item] of this.cache.entries()) {\n if (this.isExpired(item)) {\n this.cache.delete(key);\n }\n }\n\n // 清理匹配结果缓存\n for (const [key, item] of this.matchCache.entries()) {\n if (this.isExpired(item)) {\n this.matchCache.delete(key);\n }\n }\n\n // 如果缓存超过最大大小,删除最久未访问的项(LRU)\n this.evictLRU();\n }\n\n /**\n * LRU 淘汰策略\n */\n private evictLRU(): void {\n // 清理转换结果缓存\n if (this.cache.size > this.config.maxSize) {\n const sorted = Array.from(this.cache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.cache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.cache.delete(key));\n }\n\n // 清理匹配结果缓存\n if (this.matchCache.size > this.config.maxSize) {\n const sorted = Array.from(this.matchCache.entries()).sort(\n (a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt\n );\n const toDelete = sorted.slice(0, this.matchCache.size - this.config.maxSize);\n toDelete.forEach(([key]) => this.matchCache.delete(key));\n }\n }\n\n /**\n * 启动定期清理\n */\n private startCleanupInterval(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n }\n\n // 每 1 分钟清理一次过期缓存\n this.cleanupTimer = setInterval(() => {\n this.cleanup();\n }, 60 * 1000);\n }\n\n /**\n * 获取转换结果缓存\n */\n get(routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>)): TransformRoutesResult | null {\n const key = this.generateKey(routes);\n const item = this.cache.get(key);\n\n if (!item) {\n this.stats.transformMisses++;\n return null;\n }\n\n if (this.isExpired(item)) {\n this.cache.delete(key);\n this.stats.transformMisses++;\n return null;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n this.stats.transformHits++;\n\n return item.value;\n }\n\n /**\n * 设置转换结果缓存\n */\n set(\n routes: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>),\n value: TransformRoutesResult\n ): void {\n const key = this.generateKey(routes);\n const now = Date.now();\n\n const item: CacheItem<TransformRoutesResult> = {\n value,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.cache.set(key, item);\n\n // 保存到持久化存储\n if (this.persistenceEnabled) {\n this.saveToPersistence(key, value).catch((error) => {\n logger.warn('保存缓存到持久化存储失败', error);\n });\n }\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 获取路由匹配缓存\n */\n getMatch(path: string): RouteConfig | null | undefined {\n const item = this.matchCache.get(path);\n\n if (!item) {\n this.stats.matchMisses++;\n return undefined;\n }\n\n if (this.isExpired(item)) {\n this.matchCache.delete(path);\n this.stats.matchMisses++;\n return undefined;\n }\n\n // 更新访问信息\n item.lastAccessedAt = Date.now();\n item.accessCount++;\n this.stats.matchHits++;\n\n return item.value;\n }\n\n /**\n * 设置路由匹配缓存\n */\n setMatch(path: string, route: RouteConfig | null): void {\n const now = Date.now();\n\n const item: CacheItem<RouteConfig | null> = {\n value: route,\n expiresAt: now + this.config.ttl,\n createdAt: now,\n accessCount: 0,\n lastAccessedAt: now,\n };\n\n this.matchCache.set(path, item);\n\n // 检查是否需要淘汰\n this.evictLRU();\n }\n\n /**\n * 清空所有缓存\n */\n clear(): void {\n this.cache.clear();\n this.matchCache.clear();\n this.stats = {\n transformHits: 0,\n transformMisses: 0,\n matchHits: 0,\n matchMisses: 0,\n };\n logger.debug('路由缓存已清空');\n }\n\n /**\n * 销毁缓存实例并释放资源\n */\n destroy(): void {\n this.clear();\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n getStats(): {\n transformCacheSize: number;\n matchCacheSize: number;\n totalSize: number;\n hitRate: number;\n } {\n const totalHits = this.stats.transformHits + this.stats.matchHits;\n const totalAccess =\n totalHits +\n this.stats.transformMisses +\n this.stats.matchMisses;\n\n const hitRate = totalAccess > 0 ? totalHits / totalAccess : 0;\n\n return {\n transformCacheSize: this.cache.size,\n matchCacheSize: this.matchCache.size,\n totalSize: this.cache.size + this.matchCache.size,\n hitRate,\n };\n }\n}\n\n/**\n * 获取路由缓存管理器单例\n */\nlet routeCacheInstance: RouteCache | null = null;\n\nexport function getRouteCache(config?: RouteCacheConfig): RouteCache {\n if (!routeCacheInstance) {\n routeCacheInstance = new RouteCache(config);\n }\n return routeCacheInstance;\n}\n"],"names":["logger","RouteCache","initPersistence","window","persistenceEnabled","loadFromPersistence","debug","error","warn","saveToPersistence","_key","_value","generateKey","routes","name","Math","random","toString","substring","routesStr","JSON","stringify","value","hashString","str","hash","i","length","char","charCodeAt","abs","isExpired","item","Date","now","expiresAt","cleanup","key","cache","entries","delete","matchCache","evictLRU","size","config","maxSize","sorted","Array","from","sort","a","b","lastAccessedAt","toDelete","slice","forEach","startCleanupInterval","cleanupTimer","clearInterval","setInterval","get","stats","transformMisses","accessCount","transformHits","set","ttl","createdAt","catch","getMatch","path","matchMisses","undefined","matchHits","setMatch","route","clear","destroy","getStats","totalHits","totalAccess","hitRate","transformCacheSize","matchCacheSize","totalSize","Map","enablePersistence","persistenceKeyPrefix","routeCacheInstance","getRouteCache"],"mappings":"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"}
|
|
@@ -53,36 +53,49 @@ var PreloadStrategy = /*#__PURE__*/ function(PreloadStrategy) {
|
|
|
53
53
|
}({});
|
|
54
54
|
let RoutePreloader = class RoutePreloader {
|
|
55
55
|
/**
|
|
56
|
+
* 更新预加载配置
|
|
57
|
+
*/ updateConfig(config = {}) {
|
|
58
|
+
this.config = {
|
|
59
|
+
strategy: config.strategy ?? "none",
|
|
60
|
+
delay: config.delay ?? 1000,
|
|
61
|
+
priorityThreshold: config.priorityThreshold ?? 10,
|
|
62
|
+
timeout: config.timeout ?? 5000
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
shouldRegister(priority) {
|
|
66
|
+
if (this.config.strategy === "none") {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (this.config.strategy === "visible" && priority > this.config.priorityThreshold) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
registerTask(key, importFn, routeName, priority) {
|
|
75
|
+
if (!this.shouldRegister(priority)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.tasks.set(key, {
|
|
79
|
+
importFn,
|
|
80
|
+
routeName,
|
|
81
|
+
priority,
|
|
82
|
+
status: 'pending'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
56
86
|
* 注册路由用于预加载
|
|
57
87
|
*/ registerRoute(route) {
|
|
58
88
|
if (!route.page && !route.layout) {
|
|
59
89
|
return;
|
|
60
90
|
}
|
|
61
91
|
const priority = route.handle?.order ?? 999;
|
|
62
|
-
// 根据策略决定是否注册
|
|
63
|
-
if (this.config.strategy === "none") {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (this.config.strategy === "visible" && priority > this.config.priorityThreshold) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
92
|
// 注册页面组件
|
|
70
93
|
if (route.page && typeof route.page === 'function') {
|
|
71
|
-
this.
|
|
72
|
-
importFn: route.page,
|
|
73
|
-
routeName: route.name,
|
|
74
|
-
priority,
|
|
75
|
-
status: 'pending'
|
|
76
|
-
});
|
|
94
|
+
this.registerTask(`${route.name}_page`, route.page, route.name, priority);
|
|
77
95
|
}
|
|
78
96
|
// 注册布局组件
|
|
79
97
|
if (route.layout && typeof route.layout === 'function') {
|
|
80
|
-
this.
|
|
81
|
-
importFn: route.layout,
|
|
82
|
-
routeName: route.name,
|
|
83
|
-
priority,
|
|
84
|
-
status: 'pending'
|
|
85
|
-
});
|
|
98
|
+
this.registerTask(`${route.name}_layout`, route.layout, route.name, priority);
|
|
86
99
|
}
|
|
87
100
|
// 递归注册子路由
|
|
88
101
|
if (route.children) {
|
|
@@ -91,8 +104,43 @@ let RoutePreloader = class RoutePreloader {
|
|
|
91
104
|
}
|
|
92
105
|
/**
|
|
93
106
|
* 注册多个路由
|
|
94
|
-
*/ registerRoutes(routes) {
|
|
107
|
+
*/ registerRoutes(routes, resolvers) {
|
|
108
|
+
const priorityByPath = new Map();
|
|
109
|
+
const nameByPath = new Map();
|
|
110
|
+
const collectPriority = (route)=>{
|
|
111
|
+
const priority = route.handle?.order ?? 999;
|
|
112
|
+
const routeName = route.name;
|
|
113
|
+
const record = (value)=>{
|
|
114
|
+
if (typeof value !== 'string') {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (!priorityByPath.has(value) || (priorityByPath.get(value) ?? 999) > priority) {
|
|
118
|
+
priorityByPath.set(value, priority);
|
|
119
|
+
nameByPath.set(value, routeName);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
record(route.page);
|
|
123
|
+
record(route.layout);
|
|
124
|
+
record(route.error ?? route.errors);
|
|
125
|
+
record(route.loading);
|
|
126
|
+
route.children?.forEach(collectPriority);
|
|
127
|
+
};
|
|
128
|
+
routes.forEach(collectPriority);
|
|
95
129
|
routes.forEach((route)=>this.registerRoute(route));
|
|
130
|
+
if (!resolvers) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const registerResolverMap = (map, type)=>{
|
|
134
|
+
for (const [path, importFn] of map.entries()){
|
|
135
|
+
const routeName = nameByPath.get(path) ?? path;
|
|
136
|
+
const priority = priorityByPath.get(path) ?? 999;
|
|
137
|
+
this.registerTask(`${routeName}_${type}_${path}`, importFn, routeName, priority);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
registerResolverMap(resolvers.pages, 'page');
|
|
141
|
+
registerResolverMap(resolvers.layouts, 'layout');
|
|
142
|
+
registerResolverMap(resolvers.errors, 'error');
|
|
143
|
+
registerResolverMap(resolvers.loadings, 'loading');
|
|
96
144
|
}
|
|
97
145
|
/**
|
|
98
146
|
* 预加载指定路由
|
|
@@ -111,10 +159,11 @@ let RoutePreloader = class RoutePreloader {
|
|
|
111
159
|
}
|
|
112
160
|
task.status = 'loading';
|
|
113
161
|
task.startTime = Date.now();
|
|
162
|
+
let timeoutId = null;
|
|
114
163
|
try {
|
|
115
164
|
// 设置超时
|
|
116
165
|
const timeoutPromise = new Promise((_, reject)=>{
|
|
117
|
-
setTimeout(()=>reject(new Error('预加载超时')), this.config.timeout);
|
|
166
|
+
timeoutId = setTimeout(()=>reject(new Error('预加载超时')), this.config.timeout);
|
|
118
167
|
});
|
|
119
168
|
// 执行预加载
|
|
120
169
|
await Promise.race([
|
|
@@ -127,6 +176,10 @@ let RoutePreloader = class RoutePreloader {
|
|
|
127
176
|
} catch (error) {
|
|
128
177
|
task.status = 'failed';
|
|
129
178
|
_utils.logger.warn(`路由组件预加载失败: ${task.routeName}`, error);
|
|
179
|
+
} finally{
|
|
180
|
+
if (timeoutId) {
|
|
181
|
+
clearTimeout(timeoutId);
|
|
182
|
+
}
|
|
130
183
|
}
|
|
131
184
|
}
|
|
132
185
|
/**
|
|
@@ -135,8 +188,16 @@ let RoutePreloader = class RoutePreloader {
|
|
|
135
188
|
if (this.config.strategy === "none") {
|
|
136
189
|
return;
|
|
137
190
|
}
|
|
191
|
+
this.stopPreload();
|
|
138
192
|
// 延迟预加载,避免影响初始渲染
|
|
139
193
|
this.preloadTimer = setTimeout(()=>{
|
|
194
|
+
const browserWindow = typeof window !== 'undefined' ? window : undefined;
|
|
195
|
+
if (browserWindow?.requestIdleCallback) {
|
|
196
|
+
this.idleHandle = browserWindow.requestIdleCallback(()=>{
|
|
197
|
+
this.executePreload();
|
|
198
|
+
});
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
140
201
|
this.executePreload();
|
|
141
202
|
}, this.config.delay);
|
|
142
203
|
}
|
|
@@ -175,10 +236,15 @@ let RoutePreloader = class RoutePreloader {
|
|
|
175
236
|
/**
|
|
176
237
|
* 停止预加载
|
|
177
238
|
*/ stopPreload() {
|
|
239
|
+
const browserWindow = typeof window !== 'undefined' ? window : undefined;
|
|
178
240
|
if (this.preloadTimer) {
|
|
179
241
|
clearTimeout(this.preloadTimer);
|
|
180
242
|
this.preloadTimer = null;
|
|
181
243
|
}
|
|
244
|
+
if (this.idleHandle !== null && browserWindow?.cancelIdleCallback) {
|
|
245
|
+
browserWindow.cancelIdleCallback(this.idleHandle);
|
|
246
|
+
this.idleHandle = null;
|
|
247
|
+
}
|
|
182
248
|
}
|
|
183
249
|
/**
|
|
184
250
|
* 清空所有任务
|
|
@@ -206,8 +272,9 @@ let RoutePreloader = class RoutePreloader {
|
|
|
206
272
|
_define_property(this, "tasks", new Map());
|
|
207
273
|
_define_property(this, "config", void 0);
|
|
208
274
|
_define_property(this, "preloadTimer", null);
|
|
275
|
+
_define_property(this, "idleHandle", null);
|
|
209
276
|
this.config = {
|
|
210
|
-
strategy: config.strategy ?? "
|
|
277
|
+
strategy: config.strategy ?? "none",
|
|
211
278
|
delay: config.delay ?? 1000,
|
|
212
279
|
priorityThreshold: config.priorityThreshold ?? 10,
|
|
213
280
|
timeout: config.timeout ?? 5000
|