@vlian/framework 1.2.18 → 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 +28 -9
- package/dist/core/router/RouterManager.cjs.map +1 -1
- package/dist/core/router/RouterManager.d.ts +2 -2
- package/dist/core/router/RouterManager.js +28 -9
- 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/types.d.ts +9 -0
- package/dist/core/router/types.js.map +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.cjs +11 -6
- 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 +11 -6
- package/dist/core/router/utils/adapters/react-router/transform.js.map +1 -1
- package/dist/core/router/validation/RouterConfigValidator.d.ts +2 -0
- package/dist/core/router/validation/schema.cjs +2 -1
- package/dist/core/router/validation/schema.cjs.map +1 -1
- package/dist/core/router/validation/schema.d.ts +3 -0
- package/dist/core/router/validation/schema.js +2 -1
- package/dist/core/router/validation/schema.js.map +1 -1
- package/dist/index.umd.js +43 -18
- 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
package/dist/analytics.umd.js
CHANGED
|
@@ -113,14 +113,15 @@ let RouterManager = class RouterManager {
|
|
|
113
113
|
// 缓存转换结果
|
|
114
114
|
this.cache.set(cacheKey, result);
|
|
115
115
|
}
|
|
116
|
-
const
|
|
116
|
+
const enableHydrateFallback = config.enableHydrateFallback ?? Boolean(config.options?.hydrationData);
|
|
117
|
+
const reactRoutes = await (0, _transform1.transformRoutesToReactRoutes)(result.routes, result, config.defaultRouteErrorComponent, config.defaultRouteLoadingComponent, enableHydrateFallback);
|
|
117
118
|
// 注册路由到预加载器
|
|
118
119
|
if (result.routes) {
|
|
119
120
|
this.preloader.registerRoutes(result.routes, result);
|
|
120
121
|
// 开始预加载
|
|
121
122
|
this.preloader.startPreload();
|
|
122
123
|
}
|
|
123
|
-
await this.resolveInitialLazyRoutes(reactRoutes);
|
|
124
|
+
await this.resolveInitialLazyRoutes(reactRoutes, !enableHydrateFallback);
|
|
124
125
|
let routerInstance = null;
|
|
125
126
|
if (config.mode === 'browser') {
|
|
126
127
|
routerInstance = (0, _reactrouterdom.createBrowserRouter)(reactRoutes, config.options);
|
|
@@ -153,17 +154,35 @@ let RouterManager = class RouterManager {
|
|
|
153
154
|
_utils.logger.info('路由管理器初始化完成');
|
|
154
155
|
}
|
|
155
156
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*/ async resolveInitialLazyRoutes(routes) {
|
|
157
|
+
* 预解析 lazy 路由,避免首屏或重定向链路长时间停留在 hydrate fallback。
|
|
158
|
+
* resolveAll=true 时会在初始化阶段解析全部 lazy 路由。
|
|
159
|
+
*/ async resolveInitialLazyRoutes(routes, resolveAll = false) {
|
|
159
160
|
if (typeof window === 'undefined') {
|
|
160
161
|
return;
|
|
161
162
|
}
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
|
|
163
|
+
let targetRoutes = [];
|
|
164
|
+
if (resolveAll) {
|
|
165
|
+
const stack = [
|
|
166
|
+
...routes
|
|
167
|
+
];
|
|
168
|
+
while(stack.length > 0){
|
|
169
|
+
const current = stack.shift();
|
|
170
|
+
if (!current) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
targetRoutes.push(current);
|
|
174
|
+
if (current.children && current.children.length > 0) {
|
|
175
|
+
stack.push(...current.children);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
const matches = (0, _reactrouterdom.matchRoutes)(routes, window.location.pathname) ?? [];
|
|
180
|
+
if (matches.length === 0) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
targetRoutes = matches.map((match)=>match.route);
|
|
165
184
|
}
|
|
166
|
-
await Promise.all(
|
|
185
|
+
await Promise.all(targetRoutes.map(async (route)=>{
|
|
167
186
|
const lazy = route.lazy;
|
|
168
187
|
if (typeof lazy !== 'function') {
|
|
169
188
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/router/RouterManager.ts"],"sourcesContent":["import { logger } from '../../utils';\nimport type { RouterConfig } from './types';\nimport { transformRoutes } from './utils/transform';\nimport { transformRoutesToReactRoutes } from './utils/adapters/react-router/transform';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter, matchRoutes, type RouteObject } from 'react-router-dom';\nimport { RouterConfigValidator } from './validation';\nimport { getRouterLifecycleManager } from './lifecycle';\nimport { getRouterMiddlewareManager } from './middleware';\nimport { RouterError, RouterErrorCode } from './errors';\nimport { getRouteCache } from './performance/RouteCache';\nimport { getRoutePreloader } from './performance/RoutePreloader';\nimport { getRouterPluginManager, PluginLifecycleStage } from './plugin';\nimport { getRouterMonitoring } from './monitoring';\nimport { getAdapterManager } from './adapter';\nimport { createReactRouterAdapter } from './adapter/react-router';\n\nexport class RouterManager {\n private static instance: RouterManager | null = null;\n\n /**\n * 路由实例\n * 只能在 initialize 方法中赋值\n */\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 是否已初始化\n */\n private initialized = false;\n\n /**\n * 路由缓存实例\n */\n private cache = getRouteCache();\n\n /**\n * 路由预加载器实例\n */\n private preloader = getRoutePreloader();\n\n /**\n * 路由插件管理器实例\n */\n private pluginManager = getRouterPluginManager();\n\n /**\n * 路由监控服务实例\n */\n private monitoring = getRouterMonitoring();\n\n /**\n * 路由适配器管理器实例\n */\n private adapterManager = getAdapterManager();\n\n private constructor() {\n // 私有构造函数\n // 注册默认的 React Router 适配器\n this.adapterManager.register({\n name: 'react-router',\n factory: createReactRouterAdapter(),\n priority: 10,\n });\n }\n /**\n * 获取单例实例\n */\n static getInstance(): RouterManager {\n if (!RouterManager.instance) {\n RouterManager.instance = new RouterManager();\n }\n return RouterManager.instance;\n }\n /**\n * 初始化路由管理器\n * \n * @param config - 路由配置\n * @param _appInstance - 应用实例(保留用于兼容性,当前未使用)\n */\n async initialize(config: RouterConfig): Promise<void> {\n // 如果路由被禁用,直接返回\n if (config.enabled === false || config.enabled === 'disabled') {\n logger.info('路由系统已禁用');\n return;\n }\n\n // 配置验证(如果启用)\n if (config.enableValidation !== false) {\n try {\n RouterConfigValidator.validate(config);\n logger.debug('路由配置验证通过');\n } catch (error) {\n logger.error('路由配置验证失败', error);\n // 开发环境下抛出错误,生产环境下记录警告但继续执行\n if (process.env.NODE_ENV === 'development') {\n throw error;\n }\n }\n }\n\n // 执行插件钩子:路由初始化前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_INIT, {\n config,\n });\n\n // 注册生命周期钩子\n if (config.hooks) {\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.register(config.hooks);\n logger.debug('路由生命周期钩子已注册');\n }\n\n // 转换数据(使用缓存)\n if (!config.routes) {\n throw new RouterError(\n '路由配置不能为空',\n RouterErrorCode.ROUTER_CONFIG_ERROR\n );\n }\n\n // 更新预加载策略(默认关闭,按需懒加载)\n this.preloader.updateConfig(config.preload);\n this.preloader.clear();\n\n let result;\n const cacheKey = config.routes;\n const cachedResult = this.cache.get(cacheKey);\n\n if (cachedResult) {\n logger.debug('使用缓存的路由转换结果');\n result = cachedResult;\n } else {\n // 执行插件钩子:路由转换前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_TRANSFORM, {\n config,\n });\n\n result = await transformRoutes(config.routes, config.transformOptions);\n\n // 执行插件钩子:路由转换后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_TRANSFORM, {\n config,\n routes: result.routes,\n });\n\n // 缓存转换结果\n this.cache.set(cacheKey, result);\n }\n\n const reactRoutes = await transformRoutesToReactRoutes(\n result.routes,\n result,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n );\n\n // 注册路由到预加载器\n if (result.routes) {\n this.preloader.registerRoutes(result.routes, result);\n // 开始预加载\n this.preloader.startPreload();\n }\n\n await this.resolveInitialLazyRoutes(reactRoutes);\n\n let routerInstance: ReturnType<typeof createBrowserRouter> | null = null;\n if (config.mode === 'browser') {\n routerInstance = createBrowserRouter(reactRoutes, config.options);\n } else if (config.mode === 'hash') {\n routerInstance = createHashRouter(reactRoutes, config.options);\n } else if (config.mode === 'memory') {\n routerInstance = createMemoryRouter(reactRoutes, config.options);\n }\n\n if (!routerInstance) {\n throw new RouterError(\n '路由模式不支持',\n RouterErrorCode.ROUTER_CONFIG_ERROR,\n undefined,\n undefined,\n { mode: config.mode }\n );\n }\n\n // 只能在 initialize 方法中赋值\n this.router = routerInstance;\n this.initialized = true;\n\n // 执行插件钩子:路由初始化后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_INIT, {\n config,\n routes: result.routes,\n });\n\n // 记录监控:路由初始化完成\n const initialPath = typeof window !== 'undefined'\n ? `${window.location.pathname}${window.location.search}${window.location.hash}`\n : this.router?.state?.location?.pathname ?? '/';\n\n this.monitoring.trackRouteAccess(\n {\n path: initialPath,\n meta: { name: 'router-init' },\n },\n undefined,\n true\n );\n\n logger.info('路由管理器初始化完成');\n }\n\n /**\n * 预解析当前 URL 命中的 lazy 路由,避免首屏长时间停留在 hydrate fallback。\n * 非首屏路由仍保持懒加载,保留代码分割收益。\n */\n private async resolveInitialLazyRoutes(routes: RouteObject[]): Promise<void> {\n if (typeof window === 'undefined') {\n return;\n }\n\n const matches = matchRoutes(routes, window.location.pathname) ?? [];\n if (matches.length === 0) {\n return;\n }\n\n await Promise.all(\n matches.map(async ({ route }) => {\n const lazy = route.lazy;\n if (typeof lazy !== 'function') {\n return;\n }\n\n try {\n const resolved = await lazy();\n Object.assign(route, resolved);\n delete (route as RouteObject & { lazy?: unknown }).lazy;\n } catch (error) {\n logger.warn('首屏路由懒加载预解析失败,回退到 Router 默认懒加载', error);\n }\n }),\n );\n }\n\n /**\n * 获取路由实例\n * \n * @returns 路由实例,如果未初始化则返回 null\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 检查是否已初始化\n * \n * @returns 如果已初始化返回 true,否则返回 false\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 销毁路由管理器\n */\n destroy(): void {\n // 执行插件钩子:销毁\n this.pluginManager.executeHooks(PluginLifecycleStage.DESTROY, {\n config: {} as RouterConfig,\n });\n\n // 停止预加载\n this.preloader.stopPreload();\n\n this.router = null;\n this.initialized = false;\n \n // 清空生命周期钩子和中间件\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.clear();\n \n const middlewareManager = getRouterMiddlewareManager();\n middlewareManager.clear();\n \n logger.info('路由管理器已销毁');\n }\n\n /**\n * 获取路由缓存实例\n */\n getCache() {\n return this.cache;\n }\n\n /**\n * 获取路由预加载器实例\n */\n getPreloader() {\n return this.preloader;\n }\n\n /**\n * 获取路由插件管理器实例\n */\n getPluginManager() {\n return this.pluginManager;\n }\n\n /**\n * 获取路由监控服务实例\n */\n getMonitoring() {\n return this.monitoring;\n }\n}\n\n/**\n * 获取路由管理器\n */\nexport function getRouterManager(): RouterManager {\n return RouterManager.getInstance();\n}\n"],"names":["RouterManager","getRouterManager","getInstance","instance","initialize","config","enabled","logger","info","enableValidation","RouterConfigValidator","validate","debug","error","process","env","NODE_ENV","pluginManager","executeHooks","PluginLifecycleStage","BEFORE_INIT","hooks","lifecycleManager","getRouterLifecycleManager","register","routes","RouterError","RouterErrorCode","ROUTER_CONFIG_ERROR","preloader","updateConfig","preload","clear","result","cacheKey","cachedResult","cache","get","BEFORE_TRANSFORM","transformRoutes","transformOptions","AFTER_TRANSFORM","set","reactRoutes","transformRoutesToReactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","registerRoutes","startPreload","resolveInitialLazyRoutes","routerInstance","mode","createBrowserRouter","options","createHashRouter","createMemoryRouter","undefined","router","initialized","AFTER_INIT","initialPath","window","location","pathname","search","hash","state","monitoring","trackRouteAccess","path","meta","name","matches","matchRoutes","length","Promise","all","map","route","lazy","resolved","Object","assign","warn","getRouter","isInitialized","destroy","DESTROY","stopPreload","middlewareManager","getRouterMiddlewareManager","getCache","getPreloader","getPluginManager","getMonitoring","getRouteCache","getRoutePreloader","getRouterPluginManager","getRouterMonitoring","adapterManager","getAdapterManager","factory","createReactRouterAdapter","priority"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/router/RouterManager.ts"],"sourcesContent":["import { logger } from '../../utils';\nimport type { RouterConfig } from './types';\nimport { transformRoutes } from './utils/transform';\nimport { transformRoutesToReactRoutes } from './utils/adapters/react-router/transform';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter, matchRoutes, type RouteObject } from 'react-router-dom';\nimport { RouterConfigValidator } from './validation';\nimport { getRouterLifecycleManager } from './lifecycle';\nimport { getRouterMiddlewareManager } from './middleware';\nimport { RouterError, RouterErrorCode } from './errors';\nimport { getRouteCache } from './performance/RouteCache';\nimport { getRoutePreloader } from './performance/RoutePreloader';\nimport { getRouterPluginManager, PluginLifecycleStage } from './plugin';\nimport { getRouterMonitoring } from './monitoring';\nimport { getAdapterManager } from './adapter';\nimport { createReactRouterAdapter } from './adapter/react-router';\n\nexport class RouterManager {\n private static instance: RouterManager | null = null;\n\n /**\n * 路由实例\n * 只能在 initialize 方法中赋值\n */\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 是否已初始化\n */\n private initialized = false;\n\n /**\n * 路由缓存实例\n */\n private cache = getRouteCache();\n\n /**\n * 路由预加载器实例\n */\n private preloader = getRoutePreloader();\n\n /**\n * 路由插件管理器实例\n */\n private pluginManager = getRouterPluginManager();\n\n /**\n * 路由监控服务实例\n */\n private monitoring = getRouterMonitoring();\n\n /**\n * 路由适配器管理器实例\n */\n private adapterManager = getAdapterManager();\n\n private constructor() {\n // 私有构造函数\n // 注册默认的 React Router 适配器\n this.adapterManager.register({\n name: 'react-router',\n factory: createReactRouterAdapter(),\n priority: 10,\n });\n }\n /**\n * 获取单例实例\n */\n static getInstance(): RouterManager {\n if (!RouterManager.instance) {\n RouterManager.instance = new RouterManager();\n }\n return RouterManager.instance;\n }\n /**\n * 初始化路由管理器\n * \n * @param config - 路由配置\n * @param _appInstance - 应用实例(保留用于兼容性,当前未使用)\n */\n async initialize(config: RouterConfig): Promise<void> {\n // 如果路由被禁用,直接返回\n if (config.enabled === false || config.enabled === 'disabled') {\n logger.info('路由系统已禁用');\n return;\n }\n\n // 配置验证(如果启用)\n if (config.enableValidation !== false) {\n try {\n RouterConfigValidator.validate(config);\n logger.debug('路由配置验证通过');\n } catch (error) {\n logger.error('路由配置验证失败', error);\n // 开发环境下抛出错误,生产环境下记录警告但继续执行\n if (process.env.NODE_ENV === 'development') {\n throw error;\n }\n }\n }\n\n // 执行插件钩子:路由初始化前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_INIT, {\n config,\n });\n\n // 注册生命周期钩子\n if (config.hooks) {\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.register(config.hooks);\n logger.debug('路由生命周期钩子已注册');\n }\n\n // 转换数据(使用缓存)\n if (!config.routes) {\n throw new RouterError(\n '路由配置不能为空',\n RouterErrorCode.ROUTER_CONFIG_ERROR\n );\n }\n\n // 更新预加载策略(默认关闭,按需懒加载)\n this.preloader.updateConfig(config.preload);\n this.preloader.clear();\n\n let result;\n const cacheKey = config.routes;\n const cachedResult = this.cache.get(cacheKey);\n\n if (cachedResult) {\n logger.debug('使用缓存的路由转换结果');\n result = cachedResult;\n } else {\n // 执行插件钩子:路由转换前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_TRANSFORM, {\n config,\n });\n\n result = await transformRoutes(config.routes, config.transformOptions);\n\n // 执行插件钩子:路由转换后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_TRANSFORM, {\n config,\n routes: result.routes,\n });\n\n // 缓存转换结果\n this.cache.set(cacheKey, result);\n }\n\n const enableHydrateFallback =\n config.enableHydrateFallback\n ?? Boolean((config.options as { hydrationData?: unknown } | undefined)?.hydrationData);\n\n const reactRoutes = await transformRoutesToReactRoutes(\n result.routes,\n result,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n enableHydrateFallback,\n );\n\n // 注册路由到预加载器\n if (result.routes) {\n this.preloader.registerRoutes(result.routes, result);\n // 开始预加载\n this.preloader.startPreload();\n }\n\n await this.resolveInitialLazyRoutes(reactRoutes, !enableHydrateFallback);\n\n let routerInstance: ReturnType<typeof createBrowserRouter> | null = null;\n if (config.mode === 'browser') {\n routerInstance = createBrowserRouter(reactRoutes, config.options);\n } else if (config.mode === 'hash') {\n routerInstance = createHashRouter(reactRoutes, config.options);\n } else if (config.mode === 'memory') {\n routerInstance = createMemoryRouter(reactRoutes, config.options);\n }\n\n if (!routerInstance) {\n throw new RouterError(\n '路由模式不支持',\n RouterErrorCode.ROUTER_CONFIG_ERROR,\n undefined,\n undefined,\n { mode: config.mode }\n );\n }\n\n // 只能在 initialize 方法中赋值\n this.router = routerInstance;\n this.initialized = true;\n\n // 执行插件钩子:路由初始化后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_INIT, {\n config,\n routes: result.routes,\n });\n\n // 记录监控:路由初始化完成\n const initialPath = typeof window !== 'undefined'\n ? `${window.location.pathname}${window.location.search}${window.location.hash}`\n : this.router?.state?.location?.pathname ?? '/';\n\n this.monitoring.trackRouteAccess(\n {\n path: initialPath,\n meta: { name: 'router-init' },\n },\n undefined,\n true\n );\n\n logger.info('路由管理器初始化完成');\n }\n\n /**\n * 预解析 lazy 路由,避免首屏或重定向链路长时间停留在 hydrate fallback。\n * resolveAll=true 时会在初始化阶段解析全部 lazy 路由。\n */\n private async resolveInitialLazyRoutes(routes: RouteObject[], resolveAll: boolean = false): Promise<void> {\n if (typeof window === 'undefined') {\n return;\n }\n\n let targetRoutes: RouteObject[] = [];\n if (resolveAll) {\n const stack = [...routes];\n while (stack.length > 0) {\n const current = stack.shift();\n if (!current) {\n continue;\n }\n targetRoutes.push(current);\n if (current.children && current.children.length > 0) {\n stack.push(...current.children);\n }\n }\n } else {\n const matches = matchRoutes(routes, window.location.pathname) ?? [];\n if (matches.length === 0) {\n return;\n }\n targetRoutes = matches.map((match) => match.route);\n }\n\n await Promise.all(\n targetRoutes.map(async (route) => {\n const lazy = route.lazy;\n if (typeof lazy !== 'function') {\n return;\n }\n\n try {\n const resolved = await lazy();\n Object.assign(route, resolved);\n delete (route as RouteObject & { lazy?: unknown }).lazy;\n } catch (error) {\n logger.warn('首屏路由懒加载预解析失败,回退到 Router 默认懒加载', error);\n }\n }),\n );\n }\n\n /**\n * 获取路由实例\n * \n * @returns 路由实例,如果未初始化则返回 null\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 检查是否已初始化\n * \n * @returns 如果已初始化返回 true,否则返回 false\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 销毁路由管理器\n */\n destroy(): void {\n // 执行插件钩子:销毁\n this.pluginManager.executeHooks(PluginLifecycleStage.DESTROY, {\n config: {} as RouterConfig,\n });\n\n // 停止预加载\n this.preloader.stopPreload();\n\n this.router = null;\n this.initialized = false;\n \n // 清空生命周期钩子和中间件\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.clear();\n \n const middlewareManager = getRouterMiddlewareManager();\n middlewareManager.clear();\n \n logger.info('路由管理器已销毁');\n }\n\n /**\n * 获取路由缓存实例\n */\n getCache() {\n return this.cache;\n }\n\n /**\n * 获取路由预加载器实例\n */\n getPreloader() {\n return this.preloader;\n }\n\n /**\n * 获取路由插件管理器实例\n */\n getPluginManager() {\n return this.pluginManager;\n }\n\n /**\n * 获取路由监控服务实例\n */\n getMonitoring() {\n return this.monitoring;\n }\n}\n\n/**\n * 获取路由管理器\n */\nexport function getRouterManager(): RouterManager {\n return RouterManager.getInstance();\n}\n"],"names":["RouterManager","getRouterManager","getInstance","instance","initialize","config","enabled","logger","info","enableValidation","RouterConfigValidator","validate","debug","error","process","env","NODE_ENV","pluginManager","executeHooks","PluginLifecycleStage","BEFORE_INIT","hooks","lifecycleManager","getRouterLifecycleManager","register","routes","RouterError","RouterErrorCode","ROUTER_CONFIG_ERROR","preloader","updateConfig","preload","clear","result","cacheKey","cachedResult","cache","get","BEFORE_TRANSFORM","transformRoutes","transformOptions","AFTER_TRANSFORM","set","enableHydrateFallback","Boolean","options","hydrationData","reactRoutes","transformRoutesToReactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","registerRoutes","startPreload","resolveInitialLazyRoutes","routerInstance","mode","createBrowserRouter","createHashRouter","createMemoryRouter","undefined","router","initialized","AFTER_INIT","initialPath","window","location","pathname","search","hash","state","monitoring","trackRouteAccess","path","meta","name","resolveAll","targetRoutes","stack","length","current","shift","push","children","matches","matchRoutes","map","match","route","Promise","all","lazy","resolved","Object","assign","warn","getRouter","isInitialized","destroy","DESTROY","stopPreload","middlewareManager","getRouterMiddlewareManager","getCache","getPreloader","getPluginManager","getMonitoring","getRouteCache","getRoutePreloader","getRouterPluginManager","getRouterMonitoring","adapterManager","getAdapterManager","factory","createReactRouterAdapter","priority"],"mappings":"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"}
|
|
@@ -44,8 +44,8 @@ export declare class RouterManager {
|
|
|
44
44
|
*/
|
|
45
45
|
initialize(config: RouterConfig): Promise<void>;
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
47
|
+
* 预解析 lazy 路由,避免首屏或重定向链路长时间停留在 hydrate fallback。
|
|
48
|
+
* resolveAll=true 时会在初始化阶段解析全部 lazy 路由。
|
|
49
49
|
*/
|
|
50
50
|
private resolveInitialLazyRoutes;
|
|
51
51
|
/**
|
|
@@ -95,14 +95,15 @@ export class RouterManager {
|
|
|
95
95
|
// 缓存转换结果
|
|
96
96
|
this.cache.set(cacheKey, result);
|
|
97
97
|
}
|
|
98
|
-
const
|
|
98
|
+
const enableHydrateFallback = config.enableHydrateFallback ?? Boolean(config.options?.hydrationData);
|
|
99
|
+
const reactRoutes = await transformRoutesToReactRoutes(result.routes, result, config.defaultRouteErrorComponent, config.defaultRouteLoadingComponent, enableHydrateFallback);
|
|
99
100
|
// 注册路由到预加载器
|
|
100
101
|
if (result.routes) {
|
|
101
102
|
this.preloader.registerRoutes(result.routes, result);
|
|
102
103
|
// 开始预加载
|
|
103
104
|
this.preloader.startPreload();
|
|
104
105
|
}
|
|
105
|
-
await this.resolveInitialLazyRoutes(reactRoutes);
|
|
106
|
+
await this.resolveInitialLazyRoutes(reactRoutes, !enableHydrateFallback);
|
|
106
107
|
let routerInstance = null;
|
|
107
108
|
if (config.mode === 'browser') {
|
|
108
109
|
routerInstance = createBrowserRouter(reactRoutes, config.options);
|
|
@@ -135,17 +136,35 @@ export class RouterManager {
|
|
|
135
136
|
logger.info('路由管理器初始化完成');
|
|
136
137
|
}
|
|
137
138
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*/ async resolveInitialLazyRoutes(routes) {
|
|
139
|
+
* 预解析 lazy 路由,避免首屏或重定向链路长时间停留在 hydrate fallback。
|
|
140
|
+
* resolveAll=true 时会在初始化阶段解析全部 lazy 路由。
|
|
141
|
+
*/ async resolveInitialLazyRoutes(routes, resolveAll = false) {
|
|
141
142
|
if (typeof window === 'undefined') {
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
|
|
145
|
+
let targetRoutes = [];
|
|
146
|
+
if (resolveAll) {
|
|
147
|
+
const stack = [
|
|
148
|
+
...routes
|
|
149
|
+
];
|
|
150
|
+
while(stack.length > 0){
|
|
151
|
+
const current = stack.shift();
|
|
152
|
+
if (!current) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
targetRoutes.push(current);
|
|
156
|
+
if (current.children && current.children.length > 0) {
|
|
157
|
+
stack.push(...current.children);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
const matches = matchRoutes(routes, window.location.pathname) ?? [];
|
|
162
|
+
if (matches.length === 0) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
targetRoutes = matches.map((match)=>match.route);
|
|
147
166
|
}
|
|
148
|
-
await Promise.all(
|
|
167
|
+
await Promise.all(targetRoutes.map(async (route)=>{
|
|
149
168
|
const lazy = route.lazy;
|
|
150
169
|
if (typeof lazy !== 'function') {
|
|
151
170
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/router/RouterManager.ts"],"sourcesContent":["import { logger } from '../../utils';\nimport type { RouterConfig } from './types';\nimport { transformRoutes } from './utils/transform';\nimport { transformRoutesToReactRoutes } from './utils/adapters/react-router/transform';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter, matchRoutes, type RouteObject } from 'react-router-dom';\nimport { RouterConfigValidator } from './validation';\nimport { getRouterLifecycleManager } from './lifecycle';\nimport { getRouterMiddlewareManager } from './middleware';\nimport { RouterError, RouterErrorCode } from './errors';\nimport { getRouteCache } from './performance/RouteCache';\nimport { getRoutePreloader } from './performance/RoutePreloader';\nimport { getRouterPluginManager, PluginLifecycleStage } from './plugin';\nimport { getRouterMonitoring } from './monitoring';\nimport { getAdapterManager } from './adapter';\nimport { createReactRouterAdapter } from './adapter/react-router';\n\nexport class RouterManager {\n private static instance: RouterManager | null = null;\n\n /**\n * 路由实例\n * 只能在 initialize 方法中赋值\n */\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 是否已初始化\n */\n private initialized = false;\n\n /**\n * 路由缓存实例\n */\n private cache = getRouteCache();\n\n /**\n * 路由预加载器实例\n */\n private preloader = getRoutePreloader();\n\n /**\n * 路由插件管理器实例\n */\n private pluginManager = getRouterPluginManager();\n\n /**\n * 路由监控服务实例\n */\n private monitoring = getRouterMonitoring();\n\n /**\n * 路由适配器管理器实例\n */\n private adapterManager = getAdapterManager();\n\n private constructor() {\n // 私有构造函数\n // 注册默认的 React Router 适配器\n this.adapterManager.register({\n name: 'react-router',\n factory: createReactRouterAdapter(),\n priority: 10,\n });\n }\n /**\n * 获取单例实例\n */\n static getInstance(): RouterManager {\n if (!RouterManager.instance) {\n RouterManager.instance = new RouterManager();\n }\n return RouterManager.instance;\n }\n /**\n * 初始化路由管理器\n * \n * @param config - 路由配置\n * @param _appInstance - 应用实例(保留用于兼容性,当前未使用)\n */\n async initialize(config: RouterConfig): Promise<void> {\n // 如果路由被禁用,直接返回\n if (config.enabled === false || config.enabled === 'disabled') {\n logger.info('路由系统已禁用');\n return;\n }\n\n // 配置验证(如果启用)\n if (config.enableValidation !== false) {\n try {\n RouterConfigValidator.validate(config);\n logger.debug('路由配置验证通过');\n } catch (error) {\n logger.error('路由配置验证失败', error);\n // 开发环境下抛出错误,生产环境下记录警告但继续执行\n if (process.env.NODE_ENV === 'development') {\n throw error;\n }\n }\n }\n\n // 执行插件钩子:路由初始化前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_INIT, {\n config,\n });\n\n // 注册生命周期钩子\n if (config.hooks) {\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.register(config.hooks);\n logger.debug('路由生命周期钩子已注册');\n }\n\n // 转换数据(使用缓存)\n if (!config.routes) {\n throw new RouterError(\n '路由配置不能为空',\n RouterErrorCode.ROUTER_CONFIG_ERROR\n );\n }\n\n // 更新预加载策略(默认关闭,按需懒加载)\n this.preloader.updateConfig(config.preload);\n this.preloader.clear();\n\n let result;\n const cacheKey = config.routes;\n const cachedResult = this.cache.get(cacheKey);\n\n if (cachedResult) {\n logger.debug('使用缓存的路由转换结果');\n result = cachedResult;\n } else {\n // 执行插件钩子:路由转换前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_TRANSFORM, {\n config,\n });\n\n result = await transformRoutes(config.routes, config.transformOptions);\n\n // 执行插件钩子:路由转换后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_TRANSFORM, {\n config,\n routes: result.routes,\n });\n\n // 缓存转换结果\n this.cache.set(cacheKey, result);\n }\n\n const reactRoutes = await transformRoutesToReactRoutes(\n result.routes,\n result,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n );\n\n // 注册路由到预加载器\n if (result.routes) {\n this.preloader.registerRoutes(result.routes, result);\n // 开始预加载\n this.preloader.startPreload();\n }\n\n await this.resolveInitialLazyRoutes(reactRoutes);\n\n let routerInstance: ReturnType<typeof createBrowserRouter> | null = null;\n if (config.mode === 'browser') {\n routerInstance = createBrowserRouter(reactRoutes, config.options);\n } else if (config.mode === 'hash') {\n routerInstance = createHashRouter(reactRoutes, config.options);\n } else if (config.mode === 'memory') {\n routerInstance = createMemoryRouter(reactRoutes, config.options);\n }\n\n if (!routerInstance) {\n throw new RouterError(\n '路由模式不支持',\n RouterErrorCode.ROUTER_CONFIG_ERROR,\n undefined,\n undefined,\n { mode: config.mode }\n );\n }\n\n // 只能在 initialize 方法中赋值\n this.router = routerInstance;\n this.initialized = true;\n\n // 执行插件钩子:路由初始化后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_INIT, {\n config,\n routes: result.routes,\n });\n\n // 记录监控:路由初始化完成\n const initialPath = typeof window !== 'undefined'\n ? `${window.location.pathname}${window.location.search}${window.location.hash}`\n : this.router?.state?.location?.pathname ?? '/';\n\n this.monitoring.trackRouteAccess(\n {\n path: initialPath,\n meta: { name: 'router-init' },\n },\n undefined,\n true\n );\n\n logger.info('路由管理器初始化完成');\n }\n\n /**\n * 预解析当前 URL 命中的 lazy 路由,避免首屏长时间停留在 hydrate fallback。\n * 非首屏路由仍保持懒加载,保留代码分割收益。\n */\n private async resolveInitialLazyRoutes(routes: RouteObject[]): Promise<void> {\n if (typeof window === 'undefined') {\n return;\n }\n\n const matches = matchRoutes(routes, window.location.pathname) ?? [];\n if (matches.length === 0) {\n return;\n }\n\n await Promise.all(\n matches.map(async ({ route }) => {\n const lazy = route.lazy;\n if (typeof lazy !== 'function') {\n return;\n }\n\n try {\n const resolved = await lazy();\n Object.assign(route, resolved);\n delete (route as RouteObject & { lazy?: unknown }).lazy;\n } catch (error) {\n logger.warn('首屏路由懒加载预解析失败,回退到 Router 默认懒加载', error);\n }\n }),\n );\n }\n\n /**\n * 获取路由实例\n * \n * @returns 路由实例,如果未初始化则返回 null\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 检查是否已初始化\n * \n * @returns 如果已初始化返回 true,否则返回 false\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 销毁路由管理器\n */\n destroy(): void {\n // 执行插件钩子:销毁\n this.pluginManager.executeHooks(PluginLifecycleStage.DESTROY, {\n config: {} as RouterConfig,\n });\n\n // 停止预加载\n this.preloader.stopPreload();\n\n this.router = null;\n this.initialized = false;\n \n // 清空生命周期钩子和中间件\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.clear();\n \n const middlewareManager = getRouterMiddlewareManager();\n middlewareManager.clear();\n \n logger.info('路由管理器已销毁');\n }\n\n /**\n * 获取路由缓存实例\n */\n getCache() {\n return this.cache;\n }\n\n /**\n * 获取路由预加载器实例\n */\n getPreloader() {\n return this.preloader;\n }\n\n /**\n * 获取路由插件管理器实例\n */\n getPluginManager() {\n return this.pluginManager;\n }\n\n /**\n * 获取路由监控服务实例\n */\n getMonitoring() {\n return this.monitoring;\n }\n}\n\n/**\n * 获取路由管理器\n */\nexport function getRouterManager(): RouterManager {\n return RouterManager.getInstance();\n}\n"],"names":["logger","transformRoutes","transformRoutesToReactRoutes","createBrowserRouter","createHashRouter","createMemoryRouter","matchRoutes","RouterConfigValidator","getRouterLifecycleManager","getRouterMiddlewareManager","RouterError","RouterErrorCode","getRouteCache","getRoutePreloader","getRouterPluginManager","PluginLifecycleStage","getRouterMonitoring","getAdapterManager","createReactRouterAdapter","RouterManager","getInstance","instance","initialize","config","enabled","info","enableValidation","validate","debug","error","process","env","NODE_ENV","pluginManager","executeHooks","BEFORE_INIT","hooks","lifecycleManager","register","routes","ROUTER_CONFIG_ERROR","preloader","updateConfig","preload","clear","result","cacheKey","cachedResult","cache","get","BEFORE_TRANSFORM","transformOptions","AFTER_TRANSFORM","set","reactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","registerRoutes","startPreload","resolveInitialLazyRoutes","routerInstance","mode","options","undefined","router","initialized","AFTER_INIT","initialPath","window","location","pathname","search","hash","state","monitoring","trackRouteAccess","path","meta","name","matches","length","Promise","all","map","route","lazy","resolved","Object","assign","warn","getRouter","isInitialized","destroy","DESTROY","stopPreload","middlewareManager","getCache","getPreloader","getPluginManager","getMonitoring","adapterManager","factory","priority","getRouterManager"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/router/RouterManager.ts"],"sourcesContent":["import { logger } from '../../utils';\nimport type { RouterConfig } from './types';\nimport { transformRoutes } from './utils/transform';\nimport { transformRoutesToReactRoutes } from './utils/adapters/react-router/transform';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter, matchRoutes, type RouteObject } from 'react-router-dom';\nimport { RouterConfigValidator } from './validation';\nimport { getRouterLifecycleManager } from './lifecycle';\nimport { getRouterMiddlewareManager } from './middleware';\nimport { RouterError, RouterErrorCode } from './errors';\nimport { getRouteCache } from './performance/RouteCache';\nimport { getRoutePreloader } from './performance/RoutePreloader';\nimport { getRouterPluginManager, PluginLifecycleStage } from './plugin';\nimport { getRouterMonitoring } from './monitoring';\nimport { getAdapterManager } from './adapter';\nimport { createReactRouterAdapter } from './adapter/react-router';\n\nexport class RouterManager {\n private static instance: RouterManager | null = null;\n\n /**\n * 路由实例\n * 只能在 initialize 方法中赋值\n */\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 是否已初始化\n */\n private initialized = false;\n\n /**\n * 路由缓存实例\n */\n private cache = getRouteCache();\n\n /**\n * 路由预加载器实例\n */\n private preloader = getRoutePreloader();\n\n /**\n * 路由插件管理器实例\n */\n private pluginManager = getRouterPluginManager();\n\n /**\n * 路由监控服务实例\n */\n private monitoring = getRouterMonitoring();\n\n /**\n * 路由适配器管理器实例\n */\n private adapterManager = getAdapterManager();\n\n private constructor() {\n // 私有构造函数\n // 注册默认的 React Router 适配器\n this.adapterManager.register({\n name: 'react-router',\n factory: createReactRouterAdapter(),\n priority: 10,\n });\n }\n /**\n * 获取单例实例\n */\n static getInstance(): RouterManager {\n if (!RouterManager.instance) {\n RouterManager.instance = new RouterManager();\n }\n return RouterManager.instance;\n }\n /**\n * 初始化路由管理器\n * \n * @param config - 路由配置\n * @param _appInstance - 应用实例(保留用于兼容性,当前未使用)\n */\n async initialize(config: RouterConfig): Promise<void> {\n // 如果路由被禁用,直接返回\n if (config.enabled === false || config.enabled === 'disabled') {\n logger.info('路由系统已禁用');\n return;\n }\n\n // 配置验证(如果启用)\n if (config.enableValidation !== false) {\n try {\n RouterConfigValidator.validate(config);\n logger.debug('路由配置验证通过');\n } catch (error) {\n logger.error('路由配置验证失败', error);\n // 开发环境下抛出错误,生产环境下记录警告但继续执行\n if (process.env.NODE_ENV === 'development') {\n throw error;\n }\n }\n }\n\n // 执行插件钩子:路由初始化前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_INIT, {\n config,\n });\n\n // 注册生命周期钩子\n if (config.hooks) {\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.register(config.hooks);\n logger.debug('路由生命周期钩子已注册');\n }\n\n // 转换数据(使用缓存)\n if (!config.routes) {\n throw new RouterError(\n '路由配置不能为空',\n RouterErrorCode.ROUTER_CONFIG_ERROR\n );\n }\n\n // 更新预加载策略(默认关闭,按需懒加载)\n this.preloader.updateConfig(config.preload);\n this.preloader.clear();\n\n let result;\n const cacheKey = config.routes;\n const cachedResult = this.cache.get(cacheKey);\n\n if (cachedResult) {\n logger.debug('使用缓存的路由转换结果');\n result = cachedResult;\n } else {\n // 执行插件钩子:路由转换前\n await this.pluginManager.executeHooks(PluginLifecycleStage.BEFORE_TRANSFORM, {\n config,\n });\n\n result = await transformRoutes(config.routes, config.transformOptions);\n\n // 执行插件钩子:路由转换后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_TRANSFORM, {\n config,\n routes: result.routes,\n });\n\n // 缓存转换结果\n this.cache.set(cacheKey, result);\n }\n\n const enableHydrateFallback =\n config.enableHydrateFallback\n ?? Boolean((config.options as { hydrationData?: unknown } | undefined)?.hydrationData);\n\n const reactRoutes = await transformRoutesToReactRoutes(\n result.routes,\n result,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n enableHydrateFallback,\n );\n\n // 注册路由到预加载器\n if (result.routes) {\n this.preloader.registerRoutes(result.routes, result);\n // 开始预加载\n this.preloader.startPreload();\n }\n\n await this.resolveInitialLazyRoutes(reactRoutes, !enableHydrateFallback);\n\n let routerInstance: ReturnType<typeof createBrowserRouter> | null = null;\n if (config.mode === 'browser') {\n routerInstance = createBrowserRouter(reactRoutes, config.options);\n } else if (config.mode === 'hash') {\n routerInstance = createHashRouter(reactRoutes, config.options);\n } else if (config.mode === 'memory') {\n routerInstance = createMemoryRouter(reactRoutes, config.options);\n }\n\n if (!routerInstance) {\n throw new RouterError(\n '路由模式不支持',\n RouterErrorCode.ROUTER_CONFIG_ERROR,\n undefined,\n undefined,\n { mode: config.mode }\n );\n }\n\n // 只能在 initialize 方法中赋值\n this.router = routerInstance;\n this.initialized = true;\n\n // 执行插件钩子:路由初始化后\n await this.pluginManager.executeHooks(PluginLifecycleStage.AFTER_INIT, {\n config,\n routes: result.routes,\n });\n\n // 记录监控:路由初始化完成\n const initialPath = typeof window !== 'undefined'\n ? `${window.location.pathname}${window.location.search}${window.location.hash}`\n : this.router?.state?.location?.pathname ?? '/';\n\n this.monitoring.trackRouteAccess(\n {\n path: initialPath,\n meta: { name: 'router-init' },\n },\n undefined,\n true\n );\n\n logger.info('路由管理器初始化完成');\n }\n\n /**\n * 预解析 lazy 路由,避免首屏或重定向链路长时间停留在 hydrate fallback。\n * resolveAll=true 时会在初始化阶段解析全部 lazy 路由。\n */\n private async resolveInitialLazyRoutes(routes: RouteObject[], resolveAll: boolean = false): Promise<void> {\n if (typeof window === 'undefined') {\n return;\n }\n\n let targetRoutes: RouteObject[] = [];\n if (resolveAll) {\n const stack = [...routes];\n while (stack.length > 0) {\n const current = stack.shift();\n if (!current) {\n continue;\n }\n targetRoutes.push(current);\n if (current.children && current.children.length > 0) {\n stack.push(...current.children);\n }\n }\n } else {\n const matches = matchRoutes(routes, window.location.pathname) ?? [];\n if (matches.length === 0) {\n return;\n }\n targetRoutes = matches.map((match) => match.route);\n }\n\n await Promise.all(\n targetRoutes.map(async (route) => {\n const lazy = route.lazy;\n if (typeof lazy !== 'function') {\n return;\n }\n\n try {\n const resolved = await lazy();\n Object.assign(route, resolved);\n delete (route as RouteObject & { lazy?: unknown }).lazy;\n } catch (error) {\n logger.warn('首屏路由懒加载预解析失败,回退到 Router 默认懒加载', error);\n }\n }),\n );\n }\n\n /**\n * 获取路由实例\n * \n * @returns 路由实例,如果未初始化则返回 null\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 检查是否已初始化\n * \n * @returns 如果已初始化返回 true,否则返回 false\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 销毁路由管理器\n */\n destroy(): void {\n // 执行插件钩子:销毁\n this.pluginManager.executeHooks(PluginLifecycleStage.DESTROY, {\n config: {} as RouterConfig,\n });\n\n // 停止预加载\n this.preloader.stopPreload();\n\n this.router = null;\n this.initialized = false;\n \n // 清空生命周期钩子和中间件\n const lifecycleManager = getRouterLifecycleManager();\n lifecycleManager.clear();\n \n const middlewareManager = getRouterMiddlewareManager();\n middlewareManager.clear();\n \n logger.info('路由管理器已销毁');\n }\n\n /**\n * 获取路由缓存实例\n */\n getCache() {\n return this.cache;\n }\n\n /**\n * 获取路由预加载器实例\n */\n getPreloader() {\n return this.preloader;\n }\n\n /**\n * 获取路由插件管理器实例\n */\n getPluginManager() {\n return this.pluginManager;\n }\n\n /**\n * 获取路由监控服务实例\n */\n getMonitoring() {\n return this.monitoring;\n }\n}\n\n/**\n * 获取路由管理器\n */\nexport function getRouterManager(): RouterManager {\n return RouterManager.getInstance();\n}\n"],"names":["logger","transformRoutes","transformRoutesToReactRoutes","createBrowserRouter","createHashRouter","createMemoryRouter","matchRoutes","RouterConfigValidator","getRouterLifecycleManager","getRouterMiddlewareManager","RouterError","RouterErrorCode","getRouteCache","getRoutePreloader","getRouterPluginManager","PluginLifecycleStage","getRouterMonitoring","getAdapterManager","createReactRouterAdapter","RouterManager","getInstance","instance","initialize","config","enabled","info","enableValidation","validate","debug","error","process","env","NODE_ENV","pluginManager","executeHooks","BEFORE_INIT","hooks","lifecycleManager","register","routes","ROUTER_CONFIG_ERROR","preloader","updateConfig","preload","clear","result","cacheKey","cachedResult","cache","get","BEFORE_TRANSFORM","transformOptions","AFTER_TRANSFORM","set","enableHydrateFallback","Boolean","options","hydrationData","reactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","registerRoutes","startPreload","resolveInitialLazyRoutes","routerInstance","mode","undefined","router","initialized","AFTER_INIT","initialPath","window","location","pathname","search","hash","state","monitoring","trackRouteAccess","path","meta","name","resolveAll","targetRoutes","stack","length","current","shift","push","children","matches","map","match","route","Promise","all","lazy","resolved","Object","assign","warn","getRouter","isInitialized","destroy","DESTROY","stopPreload","middlewareManager","getCache","getPreloader","getPluginManager","getMonitoring","adapterManager","factory","priority","getRouterManager"],"mappings":"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"}
|
|
@@ -41,7 +41,7 @@ let ReactRouterAdapter = class ReactRouterAdapter {
|
|
|
41
41
|
*/ async initialize(config) {
|
|
42
42
|
// 转换路由配置
|
|
43
43
|
const transformResult = await (0, _transform1.transformRoutes)(config.routes);
|
|
44
|
-
const reactRoutes = await (0, _transform.transformRoutesToReactRoutes)(transformResult.routes, transformResult, config.defaultRouteErrorComponent, config.defaultRouteLoadingComponent);
|
|
44
|
+
const reactRoutes = await (0, _transform.transformRoutesToReactRoutes)(transformResult.routes, transformResult, config.defaultRouteErrorComponent, config.defaultRouteLoadingComponent, Boolean(config.options?.hydrationData));
|
|
45
45
|
// 创建路由实例
|
|
46
46
|
const mode = config.mode || 'browser';
|
|
47
47
|
if (mode === 'browser') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/core/router/adapter/react-router/ReactRouterAdapter.ts"],"sourcesContent":["/**\n * React Router 适配器实现\n */\n\nimport type { IRouterAdapter, RouterAdapterConfig } from '../types';\nimport type { RouteLocation, NavigateOptions } from '../../types';\nimport type { AppInstance } from '../../../startup/AppInstance';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter } from 'react-router-dom';\nimport { transformRoutesToReactRoutes } from '../../utils/adapters/react-router/transform';\nimport { transformRoutes } from '../../utils/transform';\nimport { logger } from '../../../../utils';\n\n/**\n * React Router 适配器\n */\nexport class ReactRouterAdapter implements IRouterAdapter {\n readonly name = 'react-router';\n readonly version = '6.0.0';\n\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 初始化适配器\n */\n async initialize(config: RouterAdapterConfig): Promise<void> {\n\n // 转换路由配置\n const transformResult = await transformRoutes(config.routes);\n const reactRoutes = await transformRoutesToReactRoutes(\n transformResult.routes,\n transformResult,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n );\n\n // 创建路由实例\n const mode = config.mode || 'browser';\n if (mode === 'browser') {\n this.router = createBrowserRouter(reactRoutes, config.options as any);\n } else if (mode === 'hash') {\n this.router = createHashRouter(reactRoutes, config.options as any);\n } else if (mode === 'memory') {\n this.router = createMemoryRouter(reactRoutes, config.options as any);\n } else {\n throw new Error(`不支持的路由模式: ${mode}`);\n }\n\n logger.debug('React Router 适配器初始化完成');\n }\n\n /**\n * 挂载到应用实例\n */\n mount(_app: AppInstance): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n // React Router 适配器通过 RouterProvider 挂载\n // 实际的挂载逻辑在 renderApp 中处理\n logger.debug('React Router 适配器已挂载');\n }\n\n /**\n * 导航到指定路径\n */\n navigate(to: string, options?: NavigateOptions): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n if (options?.replace) {\n this.router.navigate(to, { replace: true, state: options.state });\n } else {\n this.router.navigate(to, { state: options?.state });\n }\n }\n\n /**\n * 获取当前路由信息\n */\n getCurrentRoute(): RouteLocation {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n const state = this.router.state;\n const location = state.location;\n\n // 解析查询参数\n const query: Record<string, unknown> = {};\n if (location.search) {\n const params = new URLSearchParams(location.search);\n params.forEach((value, key) => {\n query[key] = value;\n });\n }\n\n return {\n path: location.pathname + location.hash,\n query,\n params: location.state as Record<string, unknown> | undefined,\n };\n }\n\n /**\n * 获取路由实例(用于 RouterProvider)\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 销毁适配器\n */\n destroy(): void {\n this.router = null;\n logger.debug('React Router 适配器已销毁');\n }\n}\n\n/**\n * 创建 React Router 适配器工厂函数\n */\nexport function createReactRouterAdapter(): (_config: RouterAdapterConfig) => IRouterAdapter {\n return (_config: RouterAdapterConfig) => {\n return new ReactRouterAdapter();\n };\n}\n"],"names":["ReactRouterAdapter","createReactRouterAdapter","initialize","config","transformResult","transformRoutes","routes","reactRoutes","transformRoutesToReactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","mode","router","createBrowserRouter","
|
|
1
|
+
{"version":3,"sources":["../../../../../src/core/router/adapter/react-router/ReactRouterAdapter.ts"],"sourcesContent":["/**\n * React Router 适配器实现\n */\n\nimport type { IRouterAdapter, RouterAdapterConfig } from '../types';\nimport type { RouteLocation, NavigateOptions } from '../../types';\nimport type { AppInstance } from '../../../startup/AppInstance';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter } from 'react-router-dom';\nimport { transformRoutesToReactRoutes } from '../../utils/adapters/react-router/transform';\nimport { transformRoutes } from '../../utils/transform';\nimport { logger } from '../../../../utils';\n\n/**\n * React Router 适配器\n */\nexport class ReactRouterAdapter implements IRouterAdapter {\n readonly name = 'react-router';\n readonly version = '6.0.0';\n\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 初始化适配器\n */\n async initialize(config: RouterAdapterConfig): Promise<void> {\n\n // 转换路由配置\n const transformResult = await transformRoutes(config.routes);\n const reactRoutes = await transformRoutesToReactRoutes(\n transformResult.routes,\n transformResult,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n Boolean((config.options as { hydrationData?: unknown } | undefined)?.hydrationData),\n );\n\n // 创建路由实例\n const mode = config.mode || 'browser';\n if (mode === 'browser') {\n this.router = createBrowserRouter(reactRoutes, config.options as any);\n } else if (mode === 'hash') {\n this.router = createHashRouter(reactRoutes, config.options as any);\n } else if (mode === 'memory') {\n this.router = createMemoryRouter(reactRoutes, config.options as any);\n } else {\n throw new Error(`不支持的路由模式: ${mode}`);\n }\n\n logger.debug('React Router 适配器初始化完成');\n }\n\n /**\n * 挂载到应用实例\n */\n mount(_app: AppInstance): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n // React Router 适配器通过 RouterProvider 挂载\n // 实际的挂载逻辑在 renderApp 中处理\n logger.debug('React Router 适配器已挂载');\n }\n\n /**\n * 导航到指定路径\n */\n navigate(to: string, options?: NavigateOptions): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n if (options?.replace) {\n this.router.navigate(to, { replace: true, state: options.state });\n } else {\n this.router.navigate(to, { state: options?.state });\n }\n }\n\n /**\n * 获取当前路由信息\n */\n getCurrentRoute(): RouteLocation {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n const state = this.router.state;\n const location = state.location;\n\n // 解析查询参数\n const query: Record<string, unknown> = {};\n if (location.search) {\n const params = new URLSearchParams(location.search);\n params.forEach((value, key) => {\n query[key] = value;\n });\n }\n\n return {\n path: location.pathname + location.hash,\n query,\n params: location.state as Record<string, unknown> | undefined,\n };\n }\n\n /**\n * 获取路由实例(用于 RouterProvider)\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 销毁适配器\n */\n destroy(): void {\n this.router = null;\n logger.debug('React Router 适配器已销毁');\n }\n}\n\n/**\n * 创建 React Router 适配器工厂函数\n */\nexport function createReactRouterAdapter(): (_config: RouterAdapterConfig) => IRouterAdapter {\n return (_config: RouterAdapterConfig) => {\n return new ReactRouterAdapter();\n };\n}\n"],"names":["ReactRouterAdapter","createReactRouterAdapter","initialize","config","transformResult","transformRoutes","routes","reactRoutes","transformRoutesToReactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","Boolean","options","hydrationData","mode","router","createBrowserRouter","createHashRouter","createMemoryRouter","Error","logger","debug","mount","_app","navigate","to","replace","state","getCurrentRoute","location","query","search","params","URLSearchParams","forEach","value","key","path","pathname","hash","getRouter","destroy","name","version","_config"],"mappings":"AAAA;;CAEC;;;;;;;;;;;QAaYA;eAAAA;;QA8GGC;eAAAA;;;gCAtH0D;2BAC7B;4BACb;uBACT;;;;;;;;;;;;;;AAKhB,IAAA,AAAMD,qBAAN,MAAMA;IAMX;;GAEC,GACD,MAAME,WAAWC,MAA2B,EAAiB;QAE3D,SAAS;QACT,MAAMC,kBAAkB,MAAMC,IAAAA,2BAAe,EAACF,OAAOG,MAAM;QAC3D,MAAMC,cAAc,MAAMC,IAAAA,uCAA4B,EACpDJ,gBAAgBE,MAAM,EACtBF,iBACAD,OAAOM,0BAA0B,EACjCN,OAAOO,4BAA4B,EACnCC,QAASR,OAAOS,OAAO,EAA8CC;QAGvE,SAAS;QACT,MAAMC,OAAOX,OAAOW,IAAI,IAAI;QAC5B,IAAIA,SAAS,WAAW;YACtB,IAAI,CAACC,MAAM,GAAGC,IAAAA,mCAAmB,EAACT,aAAaJ,OAAOS,OAAO;QAC/D,OAAO,IAAIE,SAAS,QAAQ;YAC1B,IAAI,CAACC,MAAM,GAAGE,IAAAA,gCAAgB,EAACV,aAAaJ,OAAOS,OAAO;QAC5D,OAAO,IAAIE,SAAS,UAAU;YAC5B,IAAI,CAACC,MAAM,GAAGG,IAAAA,kCAAkB,EAACX,aAAaJ,OAAOS,OAAO;QAC9D,OAAO;YACL,MAAM,IAAIO,MAAM,CAAC,UAAU,EAAEL,MAAM;QACrC;QAEAM,aAAM,CAACC,KAAK,CAAC;IACf;IAEA;;GAEC,GACDC,MAAMC,IAAiB,EAAQ;QAC7B,IAAI,CAAC,IAAI,CAACR,MAAM,EAAE;YAChB,MAAM,IAAII,MAAM;QAClB;QAEA,uCAAuC;QACvC,yBAAyB;QACzBC,aAAM,CAACC,KAAK,CAAC;IACf;IAEA;;GAEC,GACDG,SAASC,EAAU,EAAEb,OAAyB,EAAQ;QACpD,IAAI,CAAC,IAAI,CAACG,MAAM,EAAE;YAChB,MAAM,IAAII,MAAM;QAClB;QAEA,IAAIP,SAASc,SAAS;YACpB,IAAI,CAACX,MAAM,CAACS,QAAQ,CAACC,IAAI;gBAAEC,SAAS;gBAAMC,OAAOf,QAAQe,KAAK;YAAC;QACjE,OAAO;YACL,IAAI,CAACZ,MAAM,CAACS,QAAQ,CAACC,IAAI;gBAAEE,OAAOf,SAASe;YAAM;QACnD;IACF;IAEA;;GAEC,GACDC,kBAAiC;QAC/B,IAAI,CAAC,IAAI,CAACb,MAAM,EAAE;YAChB,MAAM,IAAII,MAAM;QAClB;QAEA,MAAMQ,QAAQ,IAAI,CAACZ,MAAM,CAACY,KAAK;QAC/B,MAAME,WAAWF,MAAME,QAAQ;QAE/B,SAAS;QACT,MAAMC,QAAiC,CAAC;QACxC,IAAID,SAASE,MAAM,EAAE;YACnB,MAAMC,SAAS,IAAIC,gBAAgBJ,SAASE,MAAM;YAClDC,OAAOE,OAAO,CAAC,CAACC,OAAOC;gBACrBN,KAAK,CAACM,IAAI,GAAGD;YACf;QACF;QAEA,OAAO;YACLE,MAAMR,SAASS,QAAQ,GAAGT,SAASU,IAAI;YACvCT;YACAE,QAAQH,SAASF,KAAK;QACxB;IACF;IAEA;;GAEC,GACDa,YAA2D;QACzD,OAAO,IAAI,CAACzB,MAAM;IACpB;IAEA;;GAEC,GACD0B,UAAgB;QACd,IAAI,CAAC1B,MAAM,GAAG;QACdK,aAAM,CAACC,KAAK,CAAC;IACf;;QAvGA,uBAASqB,QAAO;QAChB,uBAASC,WAAU;QAEnB,uBAAQ5B,UAAwD;;AAqGlE;AAKO,SAASd;IACd,OAAO,CAAC2C;QACN,OAAO,IAAI5C;IACb;AACF"}
|
|
@@ -25,7 +25,7 @@ import { logger } from "../../../../utils";
|
|
|
25
25
|
*/ async initialize(config) {
|
|
26
26
|
// 转换路由配置
|
|
27
27
|
const transformResult = await transformRoutes(config.routes);
|
|
28
|
-
const reactRoutes = await transformRoutesToReactRoutes(transformResult.routes, transformResult, config.defaultRouteErrorComponent, config.defaultRouteLoadingComponent);
|
|
28
|
+
const reactRoutes = await transformRoutesToReactRoutes(transformResult.routes, transformResult, config.defaultRouteErrorComponent, config.defaultRouteLoadingComponent, Boolean(config.options?.hydrationData));
|
|
29
29
|
// 创建路由实例
|
|
30
30
|
const mode = config.mode || 'browser';
|
|
31
31
|
if (mode === 'browser') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/core/router/adapter/react-router/ReactRouterAdapter.ts"],"sourcesContent":["/**\n * React Router 适配器实现\n */\n\nimport type { IRouterAdapter, RouterAdapterConfig } from '../types';\nimport type { RouteLocation, NavigateOptions } from '../../types';\nimport type { AppInstance } from '../../../startup/AppInstance';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter } from 'react-router-dom';\nimport { transformRoutesToReactRoutes } from '../../utils/adapters/react-router/transform';\nimport { transformRoutes } from '../../utils/transform';\nimport { logger } from '../../../../utils';\n\n/**\n * React Router 适配器\n */\nexport class ReactRouterAdapter implements IRouterAdapter {\n readonly name = 'react-router';\n readonly version = '6.0.0';\n\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 初始化适配器\n */\n async initialize(config: RouterAdapterConfig): Promise<void> {\n\n // 转换路由配置\n const transformResult = await transformRoutes(config.routes);\n const reactRoutes = await transformRoutesToReactRoutes(\n transformResult.routes,\n transformResult,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n );\n\n // 创建路由实例\n const mode = config.mode || 'browser';\n if (mode === 'browser') {\n this.router = createBrowserRouter(reactRoutes, config.options as any);\n } else if (mode === 'hash') {\n this.router = createHashRouter(reactRoutes, config.options as any);\n } else if (mode === 'memory') {\n this.router = createMemoryRouter(reactRoutes, config.options as any);\n } else {\n throw new Error(`不支持的路由模式: ${mode}`);\n }\n\n logger.debug('React Router 适配器初始化完成');\n }\n\n /**\n * 挂载到应用实例\n */\n mount(_app: AppInstance): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n // React Router 适配器通过 RouterProvider 挂载\n // 实际的挂载逻辑在 renderApp 中处理\n logger.debug('React Router 适配器已挂载');\n }\n\n /**\n * 导航到指定路径\n */\n navigate(to: string, options?: NavigateOptions): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n if (options?.replace) {\n this.router.navigate(to, { replace: true, state: options.state });\n } else {\n this.router.navigate(to, { state: options?.state });\n }\n }\n\n /**\n * 获取当前路由信息\n */\n getCurrentRoute(): RouteLocation {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n const state = this.router.state;\n const location = state.location;\n\n // 解析查询参数\n const query: Record<string, unknown> = {};\n if (location.search) {\n const params = new URLSearchParams(location.search);\n params.forEach((value, key) => {\n query[key] = value;\n });\n }\n\n return {\n path: location.pathname + location.hash,\n query,\n params: location.state as Record<string, unknown> | undefined,\n };\n }\n\n /**\n * 获取路由实例(用于 RouterProvider)\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 销毁适配器\n */\n destroy(): void {\n this.router = null;\n logger.debug('React Router 适配器已销毁');\n }\n}\n\n/**\n * 创建 React Router 适配器工厂函数\n */\nexport function createReactRouterAdapter(): (_config: RouterAdapterConfig) => IRouterAdapter {\n return (_config: RouterAdapterConfig) => {\n return new ReactRouterAdapter();\n };\n}\n"],"names":["createBrowserRouter","createHashRouter","createMemoryRouter","transformRoutesToReactRoutes","transformRoutes","logger","ReactRouterAdapter","initialize","config","transformResult","routes","reactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","
|
|
1
|
+
{"version":3,"sources":["../../../../../src/core/router/adapter/react-router/ReactRouterAdapter.ts"],"sourcesContent":["/**\n * React Router 适配器实现\n */\n\nimport type { IRouterAdapter, RouterAdapterConfig } from '../types';\nimport type { RouteLocation, NavigateOptions } from '../../types';\nimport type { AppInstance } from '../../../startup/AppInstance';\nimport { createBrowserRouter, createHashRouter, createMemoryRouter } from 'react-router-dom';\nimport { transformRoutesToReactRoutes } from '../../utils/adapters/react-router/transform';\nimport { transformRoutes } from '../../utils/transform';\nimport { logger } from '../../../../utils';\n\n/**\n * React Router 适配器\n */\nexport class ReactRouterAdapter implements IRouterAdapter {\n readonly name = 'react-router';\n readonly version = '6.0.0';\n\n private router: ReturnType<typeof createBrowserRouter> | null = null;\n\n /**\n * 初始化适配器\n */\n async initialize(config: RouterAdapterConfig): Promise<void> {\n\n // 转换路由配置\n const transformResult = await transformRoutes(config.routes);\n const reactRoutes = await transformRoutesToReactRoutes(\n transformResult.routes,\n transformResult,\n config.defaultRouteErrorComponent,\n config.defaultRouteLoadingComponent,\n Boolean((config.options as { hydrationData?: unknown } | undefined)?.hydrationData),\n );\n\n // 创建路由实例\n const mode = config.mode || 'browser';\n if (mode === 'browser') {\n this.router = createBrowserRouter(reactRoutes, config.options as any);\n } else if (mode === 'hash') {\n this.router = createHashRouter(reactRoutes, config.options as any);\n } else if (mode === 'memory') {\n this.router = createMemoryRouter(reactRoutes, config.options as any);\n } else {\n throw new Error(`不支持的路由模式: ${mode}`);\n }\n\n logger.debug('React Router 适配器初始化完成');\n }\n\n /**\n * 挂载到应用实例\n */\n mount(_app: AppInstance): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n // React Router 适配器通过 RouterProvider 挂载\n // 实际的挂载逻辑在 renderApp 中处理\n logger.debug('React Router 适配器已挂载');\n }\n\n /**\n * 导航到指定路径\n */\n navigate(to: string, options?: NavigateOptions): void {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n if (options?.replace) {\n this.router.navigate(to, { replace: true, state: options.state });\n } else {\n this.router.navigate(to, { state: options?.state });\n }\n }\n\n /**\n * 获取当前路由信息\n */\n getCurrentRoute(): RouteLocation {\n if (!this.router) {\n throw new Error('适配器未初始化');\n }\n\n const state = this.router.state;\n const location = state.location;\n\n // 解析查询参数\n const query: Record<string, unknown> = {};\n if (location.search) {\n const params = new URLSearchParams(location.search);\n params.forEach((value, key) => {\n query[key] = value;\n });\n }\n\n return {\n path: location.pathname + location.hash,\n query,\n params: location.state as Record<string, unknown> | undefined,\n };\n }\n\n /**\n * 获取路由实例(用于 RouterProvider)\n */\n getRouter(): ReturnType<typeof createBrowserRouter> | null {\n return this.router;\n }\n\n /**\n * 销毁适配器\n */\n destroy(): void {\n this.router = null;\n logger.debug('React Router 适配器已销毁');\n }\n}\n\n/**\n * 创建 React Router 适配器工厂函数\n */\nexport function createReactRouterAdapter(): (_config: RouterAdapterConfig) => IRouterAdapter {\n return (_config: RouterAdapterConfig) => {\n return new ReactRouterAdapter();\n };\n}\n"],"names":["createBrowserRouter","createHashRouter","createMemoryRouter","transformRoutesToReactRoutes","transformRoutes","logger","ReactRouterAdapter","initialize","config","transformResult","routes","reactRoutes","defaultRouteErrorComponent","defaultRouteLoadingComponent","Boolean","options","hydrationData","mode","router","Error","debug","mount","_app","navigate","to","replace","state","getCurrentRoute","location","query","search","params","URLSearchParams","forEach","value","key","path","pathname","hash","getRouter","destroy","name","version","createReactRouterAdapter","_config"],"mappings":"AAAA;;CAEC;;;;;;;;;;;;;AAKD,SAASA,mBAAmB,EAAEC,gBAAgB,EAAEC,kBAAkB,QAAQ,mBAAmB;AAC7F,SAASC,4BAA4B,QAAQ,8CAA8C;AAC3F,SAASC,eAAe,QAAQ,wBAAwB;AACxD,SAASC,MAAM,QAAQ,oBAAoB;AAE3C;;CAEC,GACD,OAAO,MAAMC;IAMX;;GAEC,GACD,MAAMC,WAAWC,MAA2B,EAAiB;QAE3D,SAAS;QACT,MAAMC,kBAAkB,MAAML,gBAAgBI,OAAOE,MAAM;QAC3D,MAAMC,cAAc,MAAMR,6BACxBM,gBAAgBC,MAAM,EACtBD,iBACAD,OAAOI,0BAA0B,EACjCJ,OAAOK,4BAA4B,EACnCC,QAASN,OAAOO,OAAO,EAA8CC;QAGvE,SAAS;QACT,MAAMC,OAAOT,OAAOS,IAAI,IAAI;QAC5B,IAAIA,SAAS,WAAW;YACtB,IAAI,CAACC,MAAM,GAAGlB,oBAAoBW,aAAaH,OAAOO,OAAO;QAC/D,OAAO,IAAIE,SAAS,QAAQ;YAC1B,IAAI,CAACC,MAAM,GAAGjB,iBAAiBU,aAAaH,OAAOO,OAAO;QAC5D,OAAO,IAAIE,SAAS,UAAU;YAC5B,IAAI,CAACC,MAAM,GAAGhB,mBAAmBS,aAAaH,OAAOO,OAAO;QAC9D,OAAO;YACL,MAAM,IAAII,MAAM,CAAC,UAAU,EAAEF,MAAM;QACrC;QAEAZ,OAAOe,KAAK,CAAC;IACf;IAEA;;GAEC,GACDC,MAAMC,IAAiB,EAAQ;QAC7B,IAAI,CAAC,IAAI,CAACJ,MAAM,EAAE;YAChB,MAAM,IAAIC,MAAM;QAClB;QAEA,uCAAuC;QACvC,yBAAyB;QACzBd,OAAOe,KAAK,CAAC;IACf;IAEA;;GAEC,GACDG,SAASC,EAAU,EAAET,OAAyB,EAAQ;QACpD,IAAI,CAAC,IAAI,CAACG,MAAM,EAAE;YAChB,MAAM,IAAIC,MAAM;QAClB;QAEA,IAAIJ,SAASU,SAAS;YACpB,IAAI,CAACP,MAAM,CAACK,QAAQ,CAACC,IAAI;gBAAEC,SAAS;gBAAMC,OAAOX,QAAQW,KAAK;YAAC;QACjE,OAAO;YACL,IAAI,CAACR,MAAM,CAACK,QAAQ,CAACC,IAAI;gBAAEE,OAAOX,SAASW;YAAM;QACnD;IACF;IAEA;;GAEC,GACDC,kBAAiC;QAC/B,IAAI,CAAC,IAAI,CAACT,MAAM,EAAE;YAChB,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAMO,QAAQ,IAAI,CAACR,MAAM,CAACQ,KAAK;QAC/B,MAAME,WAAWF,MAAME,QAAQ;QAE/B,SAAS;QACT,MAAMC,QAAiC,CAAC;QACxC,IAAID,SAASE,MAAM,EAAE;YACnB,MAAMC,SAAS,IAAIC,gBAAgBJ,SAASE,MAAM;YAClDC,OAAOE,OAAO,CAAC,CAACC,OAAOC;gBACrBN,KAAK,CAACM,IAAI,GAAGD;YACf;QACF;QAEA,OAAO;YACLE,MAAMR,SAASS,QAAQ,GAAGT,SAASU,IAAI;YACvCT;YACAE,QAAQH,SAASF,KAAK;QACxB;IACF;IAEA;;GAEC,GACDa,YAA2D;QACzD,OAAO,IAAI,CAACrB,MAAM;IACpB;IAEA;;GAEC,GACDsB,UAAgB;QACd,IAAI,CAACtB,MAAM,GAAG;QACdb,OAAOe,KAAK,CAAC;IACf;;QAvGA,uBAASqB,QAAO;QAChB,uBAASC,WAAU;QAEnB,uBAAQxB,UAAwD;;AAqGlE;AAEA;;CAEC,GACD,OAAO,SAASyB;IACd,OAAO,CAACC;QACN,OAAO,IAAItC;IACb;AACF"}
|
|
@@ -452,4 +452,13 @@ export interface RouterConfig {
|
|
|
452
452
|
* ```
|
|
453
453
|
*/
|
|
454
454
|
defaultRouteLoadingComponent?: ComponentImport;
|
|
455
|
+
/**
|
|
456
|
+
* 是否为路由注入 hydrateFallbackElement
|
|
457
|
+
*
|
|
458
|
+
* 默认关闭。仅在 SSR hydration 场景需要时开启。
|
|
459
|
+
* 若未显式配置,会根据 `options.hydrationData` 自动推断。
|
|
460
|
+
*
|
|
461
|
+
* @default false
|
|
462
|
+
*/
|
|
463
|
+
enableHydrateFallback?: boolean;
|
|
455
464
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/router/types.ts"],"sourcesContent":["import type { AppInstance } from '../startup/AppInstance';\nimport type { createBrowserRouter, createMemoryRouter } from 'react-router-dom';\nimport type { TransformOptions } from './utils/transform';\nimport type { PreloadConfig } from './performance/RoutePreloader';\n\nexport type RouteItemHandle = {\n title: string,\n i18nKey?: string,\n order: number,\n icon?: string,\n // 在菜单中隐藏\n hideInMenu?: boolean,\n // 隐藏尾部\n hideFooter?: boolean,\n // 保活\n keepAlive?: boolean,\n // 是否需要的登录\n needLogin?: boolean,\n // 角色\n roles?: Array<string>,\n // 路由名称,唯一Key\n name?: string,\n // 其他\n [key: string]: unknown,\n}\nexport type RouteItem = {\n // 布局 布局对象的key或动态导入函数\n layout?: string | ComponentImport | null,\n // 页面 页面对象的key或动态导入函数\n page?: string | ComponentImport | null,\n // loading 加载对象的key或动态导入函数\n loading?: string | ComponentImport | null,\n // 错误 组件的key或动态导入函数\n errors?: string | ComponentImport | null,\n // 错误(兼容字段)组件的key或动态导入函数\n error?: string | ComponentImport | null,\n // 路由名称,唯一Key\n name: string,\n // 路由\n path: string | undefined,\n // 是否分组路由\n isGroup?: boolean,\n // 是否开启重定向\n enableRedirection?: boolean,\n // 额外参数\n handle: RouteItemHandle,\n children?: RouteItem[]\n}\n\nexport type RouteMapType = Record<string, () => Promise<any>>;\n\n/**\n * DOM 路由选项类型(从 createBrowserRouter 和 createHashRouter 的参数类型提取)\n */\nexport type DOMRouterOpts = Parameters<typeof createBrowserRouter>[1];\n\n/**\n * Memory 路由选项类型(从 createMemoryRouter 的参数类型提取)\n */\nexport type MemoryRouterOpts = Parameters<typeof createMemoryRouter>[1];\n\n/**\n * 路由元数据(兼容 RouteItemHandle)\n * \n * @deprecated 建议直接使用 RouteItem 和 RouteItemHandle\n */\nexport interface RouteMeta {\n /**\n * 路由标题\n */\n title?: string;\n\n /**\n * 图标\n */\n icon?: string;\n\n /**\n * 排序\n */\n order?: number;\n\n /**\n * 权限标识\n */\n auth?: string | string[];\n\n /**\n * 是否在菜单中隐藏\n */\n hideInMenu?: boolean;\n\n /**\n * 是否启用 KeepAlive\n */\n keepAlive?: boolean;\n\n /**\n * 是否需要登录\n */\n needLogin?: boolean;\n\n /**\n * 角色列表\n */\n roles?: string[];\n\n /**\n * 路由名称(唯一标识)\n */\n name?: string;\n\n /**\n * 其他自定义元数据\n */\n [key: string]: unknown;\n}\n\n/**\n * 动态导入函数类型\n * \n * 用于懒加载组件,返回一个 Promise,resolve 后的值为组件模块对象\n * 组件必须使用默认导出(export default)\n */\nexport type ComponentImport = () => Promise<any>;\n\n/**\n * 路由配置项\n * \n * 与 RouteItem 的区别:\n * - layout、page、loading、error/errors 可以是组件路径字符串(如 \"@/pages/index.ts\")或动态导入函数\n * - 如果使用字符串,系统会自动转换为动态导入函数\n * - 如果使用函数,则直接使用,无需转换\n * - 对应的组件必须默认导出(export default xxxx)\n */\nexport interface RouteConfig {\n /**\n * 布局组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/pages/layout.tsx\" 或 \"../../pages/layout.tsx\"\n * 函数示例: () => import(\"@/pages/layout.tsx\")\n * 组件必须默认导出\n */\n layout?: string | ComponentImport | null;\n\n /**\n * 页面组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/pages/index.tsx\" 或 \"../../pages/index.tsx\"\n * 函数示例: () => import(\"@/pages/index.tsx\")\n * 组件必须默认导出\n */\n page?: string | ComponentImport | null;\n\n /**\n * 加载组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/components/Loading.tsx\"\n * 函数示例: () => import(\"@/components/Loading.tsx\")\n * 组件必须默认导出\n */\n loading?: string | ComponentImport | null;\n\n /**\n * 错误组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/pages/error.tsx\"\n * 函数示例: () => import(\"@/pages/error.tsx\")\n * 组件必须默认导出\n */\n errors?: string | ComponentImport | null;\n\n /**\n * 错误组件路径(字符串)或动态导入函数(兼容字段,优先级高于 errors)\n *\n * 字符串示例: \"@/pages/error.tsx\"\n * 函数示例: () => import(\"@/pages/error.tsx\")\n * 组件必须默认导出\n */\n error?: string | ComponentImport | null;\n\n /**\n * 路由名称(唯一标识)\n */\n name: string;\n\n /**\n * 路由路径\n */\n path: string | undefined;\n\n /**\n * 是否为路由组\n */\n isGroup?: boolean;\n\n /**\n * 是否启用重定向\n */\n enableRedirection?: boolean;\n\n /**\n * 路由元数据\n */\n handle: {\n title: string;\n i18nKey?: string;\n order: number;\n icon?: string;\n hideInMenu?: boolean;\n hideFooter?: boolean;\n keepAlive?: boolean;\n needLogin?: boolean;\n roles?: Array<string>;\n name?: string;\n [key: string]: unknown;\n };\n\n /**\n * 子路由配置\n */\n children?: RouteConfig[];\n}\n\n/**\n * 路由位置信息\n */\nexport interface RouteLocation {\n /**\n * 路径\n */\n path: string;\n\n /**\n * 路径参数\n */\n params?: Record<string, unknown>;\n\n /**\n * 查询参数\n */\n query?: Record<string, unknown>;\n\n /**\n * 路由元数据\n */\n meta?: RouteMeta;\n}\n\n/**\n * 导航选项\n */\nexport interface NavigateOptions {\n /**\n * 是否替换当前历史记录\n */\n replace?: boolean;\n\n /**\n * 状态数据\n */\n state?: unknown;\n\n /**\n * 查询参数\n */\n query?: Record<string, unknown>;\n}\n\n/**\n * 路由生命周期钩子\n */\nexport interface RouteLifecycleHooks {\n /**\n * 路由跳转前钩子\n * \n * @param to - 目标路由\n * @param from - 来源路由\n * @returns 如果返回字符串,则跳转到该路径;如果返回 false,则阻止跳转;返回 true 或 undefined 则继续跳转\n */\n beforeEach?: (to: RouteLocation, from?: RouteLocation) => string | false | void | Promise<string | false | void>;\n\n /**\n * 路由跳转后钩子\n * \n * @param to - 目标路由\n * @param from - 来源路由\n */\n afterEach?: (to: RouteLocation, from?: RouteLocation) => void | Promise<void>;\n}\n\n/**\n * 路由模式\n * \n * 对应 react-router-dom 的路由模式:\n * - `browser`: 使用 BrowserRouter(createBrowserRouter)\n * - `hash`: 使用 HashRouter(createHashRouter)\n * - `memory`: 使用 MemoryRouter(createMemoryRouter)\n */\nexport type RouterMode = 'browser' | 'hash' | 'memory';\n\n/**\n * 应用路由接口\n * \n * 这是框架核心依赖的抽象接口,所有路由实现都必须实现此接口\n */\nexport interface AppRouter {\n /**\n * 挂载到应用实例\n * \n * @param app - 应用实例\n */\n mount(app: AppInstance): void;\n\n /**\n * 路由跳转\n * \n * @param to - 目标路径或路由名称\n * @param options - 导航选项\n */\n navigate(to: string, options?: NavigateOptions): void;\n\n /**\n * 获取当前路由信息\n * \n * @returns 当前路由位置信息\n */\n getCurrentRoute(): RouteLocation;\n\n /**\n * 销毁路由实例(可选)\n */\n destroy?(): void;\n}\n\n/**\n * 路径解析配置\n */\nexport interface PathResolveConfig {\n /**\n * 项目根目录路径\n * \n * 用于解析相对路径的基准目录。\n * 如果不提供,将使用调用框架的项目根目录(通常为 process.cwd())。\n * \n * 注意:路径解析主要由构建工具(如 Vite、Webpack)处理,\n * 此配置主要用于文档和错误提示。\n * \n * @example\n * ```typescript\n * router: {\n * pathResolve: {\n * basePath: '/path/to/project',\n * },\n * }\n * ```\n */\n basePath?: string;\n\n /**\n * 路径别名映射\n * \n * 用于将路径别名(如 @/)映射到实际路径。\n * 如果不提供,将使用构建工具的配置(如 vite.config.ts 中的 resolve.alias)。\n * \n * 注意:路径别名解析主要由构建工具处理,\n * 此配置主要用于文档和错误提示。\n * \n * @example\n * ```typescript\n * router: {\n * pathResolve: {\n * pathAliases: {\n * '@': './src',\n * '@components': './src/components',\n * },\n * },\n * }\n * ```\n */\n pathAliases?: Record<string, string>;\n}\n\n/**\n * 路由配置选项\n */\nexport interface RouterConfig {\n /**\n * 是否启用路由\n * \n * - `true`: 启用内置路由(默认)\n * - `false`: 禁用内置路由,使用自定义路由\n * - `'disabled'`: 完全禁用路由\n * \n * @default true\n */\n enabled?: boolean | 'disabled';\n\n /**\n * 路由配置列表\n * \n * 使用 RouteConfig 类型\n * \n * 注意:RouteConfig 中的 layout、page、loading、error/errors 可以是:\n * - 组件路径字符串:系统会自动转换为动态导入函数\n * - 动态导入函数:直接使用,无需转换\n * \n * 路径字符串可以是:\n * - 相对路径:如 `\"./pages/index.tsx\"`、`\"../components/Layout.tsx\"`\n * - 路径别名:如 `\"@/pages/index.tsx\"`(需要在构建工具中配置,如 vite.config.ts)\n * - 绝对路径:如 `\"/src/pages/index.tsx\"`(不推荐)\n * \n * 动态导入函数示例:\n * - `() => import(\"./pages/index.tsx\")`\n * - `() => import(\"@/pages/index.tsx\")`\n * \n * 路径解析由构建工具(如 Vite、Webpack)处理,框架会在运行时验证组件是否有默认导出。\n */\n routes?: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>);\n\n /**\n * 路由模式\n * \n * - `browser`: 使用 BrowserRouter(createBrowserRouter)- 默认\n * - `hash`: 使用 HashRouter(createHashRouter)\n * - `memory`: 使用 MemoryRouter(createMemoryRouter)\n * \n * @default 'browser'\n */\n mode?: RouterMode;\n\n /**\n * 路由选项\n * \n * 传递给 react-router-dom 的路由创建方法的选项\n * - `browser` 和 `hash` 模式使用 `DOMRouterOpts`\n * - `memory` 模式使用 `MemoryRouterOpts`\n */\n options?: DOMRouterOpts | MemoryRouterOpts;\n\n /**\n * 路径解析配置\n * \n * 用于配置路径解析选项,主要用于文档和错误提示。\n * 实际的路径解析由构建工具(如 Vite、Webpack)处理。\n */\n pathResolve?: PathResolveConfig;\n\n /**\n * 转换选项\n * \n * 用于配置转换选项,主要用于转换路由配置。\n */\n transformOptions?: TransformOptions;\n\n /**\n * 路由预加载配置\n *\n * 默认策略为 `none`,即按需懒加载路由组件。\n * 如需预加载,可显式配置 `strategy` 为 `next-level` / `visible` / `all`。\n */\n preload?: PreloadConfig;\n\n /**\n * 路由生命周期钩子\n */\n hooks?: RouteLifecycleHooks;\n\n /**\n * 是否启用配置验证(默认 true)\n * \n * 如果为 false,将跳过路由配置的 Zod 验证\n */\n enableValidation?: boolean;\n\n /**\n * 默认路由错误组件\n * \n * 当路由配置中的 `error`/`errors` 为空时,将使用此组件作为错误边界。\n * 如果不提供,将使用框架内置的 `RouteErrorBoundary` 组件。\n * \n * 组件必须使用默认导出(export default)。\n * \n * @example\n * ```typescript\n * router: {\n * defaultRouteErrorComponent: () => import('./components/CustomErrorBoundary'),\n * routes: [\n * {\n * name: 'home',\n * path: '/',\n * page: './pages/Home',\n * // error/errors 为空时,将使用 defaultRouteErrorComponent\n * },\n * ],\n * },\n * ```\n */\n defaultRouteErrorComponent?: ComponentImport;\n\n /**\n * 默认路由加载组件\n * \n * 当路由配置中的 `loading` 为空时,将使用此组件作为加载指示器。\n * 如果不提供,将使用框架内置 Loading 组件。\n * \n * 组件必须使用默认导出(export default)。\n * \n * @example\n * ```typescript\n * router: {\n * defaultRouteLoadingComponent: () => import('./components/CustomLoading'),\n * routes: [\n * {\n * name: 'home',\n * path: '/',\n * page: './pages/Home',\n * // loading 为空时,将使用 defaultRouteLoadingComponent\n * },\n * ],\n * },\n * ```\n */\n defaultRouteLoadingComponent?: ComponentImport;\n}\n"],"names":[],"mappings":"AA+XA;;CAEC,GACD,WA0IC"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/router/types.ts"],"sourcesContent":["import type { AppInstance } from '../startup/AppInstance';\nimport type { createBrowserRouter, createMemoryRouter } from 'react-router-dom';\nimport type { TransformOptions } from './utils/transform';\nimport type { PreloadConfig } from './performance/RoutePreloader';\n\nexport type RouteItemHandle = {\n title: string,\n i18nKey?: string,\n order: number,\n icon?: string,\n // 在菜单中隐藏\n hideInMenu?: boolean,\n // 隐藏尾部\n hideFooter?: boolean,\n // 保活\n keepAlive?: boolean,\n // 是否需要的登录\n needLogin?: boolean,\n // 角色\n roles?: Array<string>,\n // 路由名称,唯一Key\n name?: string,\n // 其他\n [key: string]: unknown,\n}\nexport type RouteItem = {\n // 布局 布局对象的key或动态导入函数\n layout?: string | ComponentImport | null,\n // 页面 页面对象的key或动态导入函数\n page?: string | ComponentImport | null,\n // loading 加载对象的key或动态导入函数\n loading?: string | ComponentImport | null,\n // 错误 组件的key或动态导入函数\n errors?: string | ComponentImport | null,\n // 错误(兼容字段)组件的key或动态导入函数\n error?: string | ComponentImport | null,\n // 路由名称,唯一Key\n name: string,\n // 路由\n path: string | undefined,\n // 是否分组路由\n isGroup?: boolean,\n // 是否开启重定向\n enableRedirection?: boolean,\n // 额外参数\n handle: RouteItemHandle,\n children?: RouteItem[]\n}\n\nexport type RouteMapType = Record<string, () => Promise<any>>;\n\n/**\n * DOM 路由选项类型(从 createBrowserRouter 和 createHashRouter 的参数类型提取)\n */\nexport type DOMRouterOpts = Parameters<typeof createBrowserRouter>[1];\n\n/**\n * Memory 路由选项类型(从 createMemoryRouter 的参数类型提取)\n */\nexport type MemoryRouterOpts = Parameters<typeof createMemoryRouter>[1];\n\n/**\n * 路由元数据(兼容 RouteItemHandle)\n * \n * @deprecated 建议直接使用 RouteItem 和 RouteItemHandle\n */\nexport interface RouteMeta {\n /**\n * 路由标题\n */\n title?: string;\n\n /**\n * 图标\n */\n icon?: string;\n\n /**\n * 排序\n */\n order?: number;\n\n /**\n * 权限标识\n */\n auth?: string | string[];\n\n /**\n * 是否在菜单中隐藏\n */\n hideInMenu?: boolean;\n\n /**\n * 是否启用 KeepAlive\n */\n keepAlive?: boolean;\n\n /**\n * 是否需要登录\n */\n needLogin?: boolean;\n\n /**\n * 角色列表\n */\n roles?: string[];\n\n /**\n * 路由名称(唯一标识)\n */\n name?: string;\n\n /**\n * 其他自定义元数据\n */\n [key: string]: unknown;\n}\n\n/**\n * 动态导入函数类型\n * \n * 用于懒加载组件,返回一个 Promise,resolve 后的值为组件模块对象\n * 组件必须使用默认导出(export default)\n */\nexport type ComponentImport = () => Promise<any>;\n\n/**\n * 路由配置项\n * \n * 与 RouteItem 的区别:\n * - layout、page、loading、error/errors 可以是组件路径字符串(如 \"@/pages/index.ts\")或动态导入函数\n * - 如果使用字符串,系统会自动转换为动态导入函数\n * - 如果使用函数,则直接使用,无需转换\n * - 对应的组件必须默认导出(export default xxxx)\n */\nexport interface RouteConfig {\n /**\n * 布局组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/pages/layout.tsx\" 或 \"../../pages/layout.tsx\"\n * 函数示例: () => import(\"@/pages/layout.tsx\")\n * 组件必须默认导出\n */\n layout?: string | ComponentImport | null;\n\n /**\n * 页面组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/pages/index.tsx\" 或 \"../../pages/index.tsx\"\n * 函数示例: () => import(\"@/pages/index.tsx\")\n * 组件必须默认导出\n */\n page?: string | ComponentImport | null;\n\n /**\n * 加载组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/components/Loading.tsx\"\n * 函数示例: () => import(\"@/components/Loading.tsx\")\n * 组件必须默认导出\n */\n loading?: string | ComponentImport | null;\n\n /**\n * 错误组件路径(字符串)或动态导入函数\n * \n * 字符串示例: \"@/pages/error.tsx\"\n * 函数示例: () => import(\"@/pages/error.tsx\")\n * 组件必须默认导出\n */\n errors?: string | ComponentImport | null;\n\n /**\n * 错误组件路径(字符串)或动态导入函数(兼容字段,优先级高于 errors)\n *\n * 字符串示例: \"@/pages/error.tsx\"\n * 函数示例: () => import(\"@/pages/error.tsx\")\n * 组件必须默认导出\n */\n error?: string | ComponentImport | null;\n\n /**\n * 路由名称(唯一标识)\n */\n name: string;\n\n /**\n * 路由路径\n */\n path: string | undefined;\n\n /**\n * 是否为路由组\n */\n isGroup?: boolean;\n\n /**\n * 是否启用重定向\n */\n enableRedirection?: boolean;\n\n /**\n * 路由元数据\n */\n handle: {\n title: string;\n i18nKey?: string;\n order: number;\n icon?: string;\n hideInMenu?: boolean;\n hideFooter?: boolean;\n keepAlive?: boolean;\n needLogin?: boolean;\n roles?: Array<string>;\n name?: string;\n [key: string]: unknown;\n };\n\n /**\n * 子路由配置\n */\n children?: RouteConfig[];\n}\n\n/**\n * 路由位置信息\n */\nexport interface RouteLocation {\n /**\n * 路径\n */\n path: string;\n\n /**\n * 路径参数\n */\n params?: Record<string, unknown>;\n\n /**\n * 查询参数\n */\n query?: Record<string, unknown>;\n\n /**\n * 路由元数据\n */\n meta?: RouteMeta;\n}\n\n/**\n * 导航选项\n */\nexport interface NavigateOptions {\n /**\n * 是否替换当前历史记录\n */\n replace?: boolean;\n\n /**\n * 状态数据\n */\n state?: unknown;\n\n /**\n * 查询参数\n */\n query?: Record<string, unknown>;\n}\n\n/**\n * 路由生命周期钩子\n */\nexport interface RouteLifecycleHooks {\n /**\n * 路由跳转前钩子\n * \n * @param to - 目标路由\n * @param from - 来源路由\n * @returns 如果返回字符串,则跳转到该路径;如果返回 false,则阻止跳转;返回 true 或 undefined 则继续跳转\n */\n beforeEach?: (to: RouteLocation, from?: RouteLocation) => string | false | void | Promise<string | false | void>;\n\n /**\n * 路由跳转后钩子\n * \n * @param to - 目标路由\n * @param from - 来源路由\n */\n afterEach?: (to: RouteLocation, from?: RouteLocation) => void | Promise<void>;\n}\n\n/**\n * 路由模式\n * \n * 对应 react-router-dom 的路由模式:\n * - `browser`: 使用 BrowserRouter(createBrowserRouter)\n * - `hash`: 使用 HashRouter(createHashRouter)\n * - `memory`: 使用 MemoryRouter(createMemoryRouter)\n */\nexport type RouterMode = 'browser' | 'hash' | 'memory';\n\n/**\n * 应用路由接口\n * \n * 这是框架核心依赖的抽象接口,所有路由实现都必须实现此接口\n */\nexport interface AppRouter {\n /**\n * 挂载到应用实例\n * \n * @param app - 应用实例\n */\n mount(app: AppInstance): void;\n\n /**\n * 路由跳转\n * \n * @param to - 目标路径或路由名称\n * @param options - 导航选项\n */\n navigate(to: string, options?: NavigateOptions): void;\n\n /**\n * 获取当前路由信息\n * \n * @returns 当前路由位置信息\n */\n getCurrentRoute(): RouteLocation;\n\n /**\n * 销毁路由实例(可选)\n */\n destroy?(): void;\n}\n\n/**\n * 路径解析配置\n */\nexport interface PathResolveConfig {\n /**\n * 项目根目录路径\n * \n * 用于解析相对路径的基准目录。\n * 如果不提供,将使用调用框架的项目根目录(通常为 process.cwd())。\n * \n * 注意:路径解析主要由构建工具(如 Vite、Webpack)处理,\n * 此配置主要用于文档和错误提示。\n * \n * @example\n * ```typescript\n * router: {\n * pathResolve: {\n * basePath: '/path/to/project',\n * },\n * }\n * ```\n */\n basePath?: string;\n\n /**\n * 路径别名映射\n * \n * 用于将路径别名(如 @/)映射到实际路径。\n * 如果不提供,将使用构建工具的配置(如 vite.config.ts 中的 resolve.alias)。\n * \n * 注意:路径别名解析主要由构建工具处理,\n * 此配置主要用于文档和错误提示。\n * \n * @example\n * ```typescript\n * router: {\n * pathResolve: {\n * pathAliases: {\n * '@': './src',\n * '@components': './src/components',\n * },\n * },\n * }\n * ```\n */\n pathAliases?: Record<string, string>;\n}\n\n/**\n * 路由配置选项\n */\nexport interface RouterConfig {\n /**\n * 是否启用路由\n * \n * - `true`: 启用内置路由(默认)\n * - `false`: 禁用内置路由,使用自定义路由\n * - `'disabled'`: 完全禁用路由\n * \n * @default true\n */\n enabled?: boolean | 'disabled';\n\n /**\n * 路由配置列表\n * \n * 使用 RouteConfig 类型\n * \n * 注意:RouteConfig 中的 layout、page、loading、error/errors 可以是:\n * - 组件路径字符串:系统会自动转换为动态导入函数\n * - 动态导入函数:直接使用,无需转换\n * \n * 路径字符串可以是:\n * - 相对路径:如 `\"./pages/index.tsx\"`、`\"../components/Layout.tsx\"`\n * - 路径别名:如 `\"@/pages/index.tsx\"`(需要在构建工具中配置,如 vite.config.ts)\n * - 绝对路径:如 `\"/src/pages/index.tsx\"`(不推荐)\n * \n * 动态导入函数示例:\n * - `() => import(\"./pages/index.tsx\")`\n * - `() => import(\"@/pages/index.tsx\")`\n * \n * 路径解析由构建工具(如 Vite、Webpack)处理,框架会在运行时验证组件是否有默认导出。\n */\n routes?: RouteConfig[] | (() => RouteConfig[] | Promise<RouteConfig[]>);\n\n /**\n * 路由模式\n * \n * - `browser`: 使用 BrowserRouter(createBrowserRouter)- 默认\n * - `hash`: 使用 HashRouter(createHashRouter)\n * - `memory`: 使用 MemoryRouter(createMemoryRouter)\n * \n * @default 'browser'\n */\n mode?: RouterMode;\n\n /**\n * 路由选项\n * \n * 传递给 react-router-dom 的路由创建方法的选项\n * - `browser` 和 `hash` 模式使用 `DOMRouterOpts`\n * - `memory` 模式使用 `MemoryRouterOpts`\n */\n options?: DOMRouterOpts | MemoryRouterOpts;\n\n /**\n * 路径解析配置\n * \n * 用于配置路径解析选项,主要用于文档和错误提示。\n * 实际的路径解析由构建工具(如 Vite、Webpack)处理。\n */\n pathResolve?: PathResolveConfig;\n\n /**\n * 转换选项\n * \n * 用于配置转换选项,主要用于转换路由配置。\n */\n transformOptions?: TransformOptions;\n\n /**\n * 路由预加载配置\n *\n * 默认策略为 `none`,即按需懒加载路由组件。\n * 如需预加载,可显式配置 `strategy` 为 `next-level` / `visible` / `all`。\n */\n preload?: PreloadConfig;\n\n /**\n * 路由生命周期钩子\n */\n hooks?: RouteLifecycleHooks;\n\n /**\n * 是否启用配置验证(默认 true)\n * \n * 如果为 false,将跳过路由配置的 Zod 验证\n */\n enableValidation?: boolean;\n\n /**\n * 默认路由错误组件\n * \n * 当路由配置中的 `error`/`errors` 为空时,将使用此组件作为错误边界。\n * 如果不提供,将使用框架内置的 `RouteErrorBoundary` 组件。\n * \n * 组件必须使用默认导出(export default)。\n * \n * @example\n * ```typescript\n * router: {\n * defaultRouteErrorComponent: () => import('./components/CustomErrorBoundary'),\n * routes: [\n * {\n * name: 'home',\n * path: '/',\n * page: './pages/Home',\n * // error/errors 为空时,将使用 defaultRouteErrorComponent\n * },\n * ],\n * },\n * ```\n */\n defaultRouteErrorComponent?: ComponentImport;\n\n /**\n * 默认路由加载组件\n * \n * 当路由配置中的 `loading` 为空时,将使用此组件作为加载指示器。\n * 如果不提供,将使用框架内置 Loading 组件。\n * \n * 组件必须使用默认导出(export default)。\n * \n * @example\n * ```typescript\n * router: {\n * defaultRouteLoadingComponent: () => import('./components/CustomLoading'),\n * routes: [\n * {\n * name: 'home',\n * path: '/',\n * page: './pages/Home',\n * // loading 为空时,将使用 defaultRouteLoadingComponent\n * },\n * ],\n * },\n * ```\n */\n defaultRouteLoadingComponent?: ComponentImport;\n\n /**\n * 是否为路由注入 hydrateFallbackElement\n *\n * 默认关闭。仅在 SSR hydration 场景需要时开启。\n * 若未显式配置,会根据 `options.hydrationData` 自动推断。\n *\n * @default false\n */\n enableHydrateFallback?: boolean;\n}\n"],"names":[],"mappings":"AA+XA;;CAEC,GACD,WAoJC"}
|
|
@@ -22,7 +22,7 @@ function DefaultRouteHydrateFallback() {
|
|
|
22
22
|
children: "Loading..."
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
-
const transformRoutesToReactRoutes = async (routes, transformResult, defaultRouteErrorComponent, defaultRouteLoadingComponent)=>{
|
|
25
|
+
const transformRoutesToReactRoutes = async (routes, transformResult, defaultRouteErrorComponent, defaultRouteLoadingComponent, enableHydrateFallback = false)=>{
|
|
26
26
|
/**
|
|
27
27
|
* 批量处理路由
|
|
28
28
|
* @param routes 路由组
|
|
@@ -158,28 +158,31 @@ const transformRoutesToReactRoutes = async (routes, transformResult, defaultRout
|
|
|
158
158
|
}
|
|
159
159
|
const reactRoute = {
|
|
160
160
|
children: [],
|
|
161
|
-
hydrateFallbackElement: /*#__PURE__*/ (0, _jsxruntime.jsx)(DefaultRouteHydrateFallback, {}),
|
|
162
161
|
id: name,
|
|
163
162
|
handle: getHandle(),
|
|
164
163
|
lazy: async ()=>{
|
|
165
164
|
const ErrorBoundary = await getErrorComponent();
|
|
166
165
|
const config = await getConfig();
|
|
167
166
|
const LoadingComponent = await getLoadingComponent();
|
|
167
|
+
const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;
|
|
168
168
|
// 如果配置为空,确保至少返回一个空对象,避免展开 undefined
|
|
169
169
|
if (!config) {
|
|
170
170
|
return {
|
|
171
171
|
ErrorBoundary: ErrorBoundary?.default,
|
|
172
|
-
HydrateFallback
|
|
172
|
+
HydrateFallback
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
return {
|
|
176
176
|
ErrorBoundary: ErrorBoundary?.default,
|
|
177
|
-
HydrateFallback
|
|
177
|
+
HydrateFallback,
|
|
178
178
|
...config
|
|
179
179
|
};
|
|
180
180
|
},
|
|
181
181
|
path
|
|
182
182
|
};
|
|
183
|
+
if (enableHydrateFallback) {
|
|
184
|
+
reactRoute.hydrateFallbackElement = /*#__PURE__*/ (0, _jsxruntime.jsx)(DefaultRouteHydrateFallback, {});
|
|
185
|
+
}
|
|
183
186
|
// 处理子路由
|
|
184
187
|
if (children?.length) {
|
|
185
188
|
reactRoute.children = children.flatMap((child)=>transformRouteToReactRoute(child)).sort((a, b)=>{
|
|
@@ -194,9 +197,10 @@ const transformRoutesToReactRoutes = async (routes, transformResult, defaultRout
|
|
|
194
197
|
lazy: async ()=>{
|
|
195
198
|
const ErrorBoundary = await getErrorComponent();
|
|
196
199
|
const LoadingComponent = await getLoadingComponent();
|
|
200
|
+
const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;
|
|
197
201
|
return {
|
|
198
202
|
ErrorBoundary: ErrorBoundary?.default,
|
|
199
|
-
HydrateFallback
|
|
203
|
+
HydrateFallback,
|
|
200
204
|
...await getConfig(true)
|
|
201
205
|
};
|
|
202
206
|
}
|
|
@@ -226,9 +230,10 @@ const transformRoutesToReactRoutes = async (routes, transformResult, defaultRout
|
|
|
226
230
|
lazy: async ()=>{
|
|
227
231
|
const ErrorBoundary = await getErrorComponent();
|
|
228
232
|
const LoadingComponent = await getLoadingComponent();
|
|
233
|
+
const HydrateFallback = LoadingComponent?.default ?? DefaultRouteHydrateFallback;
|
|
229
234
|
return {
|
|
230
235
|
ErrorBoundary: ErrorBoundary?.default,
|
|
231
|
-
HydrateFallback
|
|
236
|
+
HydrateFallback,
|
|
232
237
|
...await getConfig(true)
|
|
233
238
|
};
|
|
234
239
|
}
|