@vlian/framework 1.2.37 → 1.2.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics.umd.js +1 -1
- package/dist/core/Test.cjs +2 -2
- package/dist/core/Test.cjs.map +1 -1
- package/dist/core/Test.js +1 -1
- package/dist/core/Test.js.map +1 -1
- package/dist/core/config/ConfigLoader.cjs +7 -7
- package/dist/core/config/ConfigLoader.cjs.map +1 -1
- package/dist/core/config/ConfigLoader.js +1 -1
- package/dist/core/config/ConfigLoader.js.map +1 -1
- package/dist/core/error/ErrorBoundary.cjs +6 -6
- package/dist/core/error/ErrorBoundary.cjs.map +1 -1
- package/dist/core/error/ErrorBoundary.d.ts +1 -1
- package/dist/core/error/ErrorBoundary.js +2 -2
- package/dist/core/error/ErrorBoundary.js.map +1 -1
- package/dist/core/error/ErrorHandler.cjs +19 -19
- package/dist/core/error/ErrorHandler.cjs.map +1 -1
- package/dist/core/error/ErrorHandler.d.ts +1 -1
- package/dist/core/error/ErrorHandler.js +2 -2
- package/dist/core/error/ErrorHandler.js.map +1 -1
- package/dist/core/event/AppEventBus.cjs +5 -5
- package/dist/core/event/AppEventBus.cjs.map +1 -1
- package/dist/core/event/AppEventBus.js +1 -1
- package/dist/core/event/AppEventBus.js.map +1 -1
- package/dist/core/initialization/InitializationErrorThrower.cjs.map +1 -1
- package/dist/core/initialization/InitializationErrorThrower.js.map +1 -1
- package/dist/core/initialization/initialization.cjs +3 -3
- package/dist/core/initialization/initialization.cjs.map +1 -1
- package/dist/core/initialization/initialization.d.ts +1 -1
- package/dist/core/initialization/initialization.js +1 -1
- package/dist/core/initialization/initialization.js.map +1 -1
- package/dist/core/initialization/initializationErrorState.cjs +2 -2
- package/dist/core/initialization/initializationErrorState.cjs.map +1 -1
- package/dist/core/initialization/initializationErrorState.d.ts +1 -1
- package/dist/core/initialization/initializationErrorState.js +1 -1
- package/dist/core/initialization/initializationErrorState.js.map +1 -1
- package/dist/core/kernel/defaultAdapters.cjs +14 -13
- package/dist/core/kernel/defaultAdapters.cjs.map +1 -1
- package/dist/core/kernel/defaultAdapters.js +2 -1
- package/dist/core/kernel/defaultAdapters.js.map +1 -1
- package/dist/core/kernel/types.d.ts +1 -1
- package/dist/core/kernel/types.js.map +1 -1
- package/dist/core/router/RouterManager.cjs +9 -9
- package/dist/core/router/RouterManager.cjs.map +1 -1
- package/dist/core/router/RouterManager.js +1 -1
- package/dist/core/router/RouterManager.js.map +1 -1
- package/dist/core/router/adapter/AdapterManager.cjs +10 -10
- package/dist/core/router/adapter/AdapterManager.cjs.map +1 -1
- package/dist/core/router/adapter/AdapterManager.js +1 -1
- package/dist/core/router/adapter/AdapterManager.js.map +1 -1
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.cjs +4 -4
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.cjs.map +1 -1
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.js +1 -1
- package/dist/core/router/adapter/react-router/ReactRouterAdapter.js.map +1 -1
- package/dist/core/router/dynamic/DynamicRouteManager.cjs +8 -8
- package/dist/core/router/dynamic/DynamicRouteManager.cjs.map +1 -1
- package/dist/core/router/dynamic/DynamicRouteManager.js +1 -1
- package/dist/core/router/dynamic/DynamicRouteManager.js.map +1 -1
- package/dist/core/router/errors/RouterError.cjs.map +1 -1
- package/dist/core/router/errors/RouterError.d.ts +4 -3
- package/dist/core/router/errors/RouterError.js.map +1 -1
- package/dist/core/router/lifecycle/RouterLifecycleManager.cjs +8 -8
- package/dist/core/router/lifecycle/RouterLifecycleManager.cjs.map +1 -1
- package/dist/core/router/lifecycle/RouterLifecycleManager.js +1 -1
- package/dist/core/router/lifecycle/RouterLifecycleManager.js.map +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.cjs +11 -11
- package/dist/core/router/middleware/RouterMiddlewareManager.cjs.map +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.js +1 -1
- package/dist/core/router/middleware/RouterMiddlewareManager.js.map +1 -1
- package/dist/core/router/middleware/auth.cjs +4 -4
- package/dist/core/router/middleware/auth.cjs.map +1 -1
- package/dist/core/router/middleware/auth.js +1 -1
- package/dist/core/router/middleware/auth.js.map +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.cjs +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.cjs.map +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.js +1 -1
- package/dist/core/router/monitoring/RouterMonitoring.js.map +1 -1
- package/dist/core/router/navigation/RouterNavigation.cjs +7 -7
- package/dist/core/router/navigation/RouterNavigation.cjs.map +1 -1
- package/dist/core/router/navigation/RouterNavigation.js +1 -1
- package/dist/core/router/navigation/RouterNavigation.js.map +1 -1
- package/dist/core/router/performance/RouteCache.cjs +7 -7
- package/dist/core/router/performance/RouteCache.cjs.map +1 -1
- package/dist/core/router/performance/RouteCache.js +1 -1
- package/dist/core/router/performance/RouteCache.js.map +1 -1
- package/dist/core/router/performance/RoutePreloader.cjs +6 -6
- package/dist/core/router/performance/RoutePreloader.cjs.map +1 -1
- package/dist/core/router/performance/RoutePreloader.js +1 -1
- package/dist/core/router/performance/RoutePreloader.js.map +1 -1
- package/dist/core/router/plugin/RouterPluginManager.cjs +8 -8
- package/dist/core/router/plugin/RouterPluginManager.cjs.map +1 -1
- package/dist/core/router/plugin/RouterPluginManager.js +1 -1
- package/dist/core/router/plugin/RouterPluginManager.js.map +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.cjs +2 -2
- package/dist/core/router/utils/adapters/react-router/transform.cjs.map +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.js +1 -1
- package/dist/core/router/utils/adapters/react-router/transform.js.map +1 -1
- package/dist/core/router/utils/transform.cjs +13 -12
- package/dist/core/router/utils/transform.cjs.map +1 -1
- package/dist/core/router/utils/transform.js +2 -1
- package/dist/core/router/utils/transform.js.map +1 -1
- package/dist/core/router/validation/RouterConfigValidator.cjs +2 -2
- package/dist/core/router/validation/RouterConfigValidator.cjs.map +1 -1
- package/dist/core/router/validation/RouterConfigValidator.js +1 -1
- package/dist/core/router/validation/RouterConfigValidator.js.map +1 -1
- package/dist/core/router/version/RouteVersionManager.cjs +6 -6
- package/dist/core/router/version/RouteVersionManager.cjs.map +1 -1
- package/dist/core/router/version/RouteVersionManager.js +1 -1
- package/dist/core/router/version/RouteVersionManager.js.map +1 -1
- package/dist/core/splash/SplashScreen.cjs +4 -4
- package/dist/core/splash/SplashScreen.cjs.map +1 -1
- package/dist/core/splash/SplashScreen.js +1 -1
- package/dist/core/splash/SplashScreen.js.map +1 -1
- package/dist/core/startup/initializeServices.cjs +14 -14
- package/dist/core/startup/initializeServices.cjs.map +1 -1
- package/dist/core/startup/initializeServices.d.ts +1 -1
- package/dist/core/startup/initializeServices.js +2 -2
- package/dist/core/startup/initializeServices.js.map +1 -1
- package/dist/core/startup/renderApp.cjs +2 -2
- package/dist/core/startup/renderApp.cjs.map +1 -1
- package/dist/core/startup/renderApp.js +1 -1
- package/dist/core/startup/renderApp.js.map +1 -1
- package/dist/core/startup/startApp.cjs +22 -22
- package/dist/core/startup/startApp.cjs.map +1 -1
- package/dist/core/startup/startApp.js +2 -2
- package/dist/core/startup/startApp.js.map +1 -1
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js.map +1 -1
- package/dist/index.cjs +0 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -8
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1389 -1486
- package/dist/index.umd.js.map +1 -1
- package/dist/kernel/constants.cjs +2 -2
- package/dist/kernel/constants.cjs.map +1 -1
- package/dist/kernel/constants.js +1 -1
- package/dist/kernel/constants.js.map +1 -1
- package/dist/kernel/manager/loggerManager.cjs +10 -10
- package/dist/kernel/manager/loggerManager.cjs.map +1 -1
- package/dist/kernel/manager/loggerManager.d.ts +1 -1
- package/dist/kernel/manager/loggerManager.js +1 -1
- package/dist/kernel/manager/loggerManager.js.map +1 -1
- package/dist/kernel/types.d.ts +1 -1
- package/dist/kernel/types.js.map +1 -1
- package/dist/library/storage/encryption.cjs +12 -13
- package/dist/library/storage/encryption.cjs.map +1 -1
- package/dist/library/storage/encryption.js +1 -2
- package/dist/library/storage/encryption.js.map +1 -1
- package/dist/state.umd.js +1 -1
- package/dist/utils/errors.cjs +71 -15
- package/dist/utils/errors.cjs.map +1 -1
- package/dist/utils/errors.d.ts +30 -1
- package/dist/utils/errors.js +16 -1
- package/dist/utils/errors.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "SplashScreen", {
|
|
|
10
10
|
});
|
|
11
11
|
const _jsxruntime = require("react/jsx-runtime");
|
|
12
12
|
const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
|
|
13
|
-
const
|
|
13
|
+
const _logger = require("@vlian/logger");
|
|
14
14
|
const _initialization = require("../initialization");
|
|
15
15
|
function _getRequireWildcardCache(nodeInterop) {
|
|
16
16
|
if (typeof WeakMap !== "function") return null;
|
|
@@ -135,12 +135,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
135
135
|
setIsInitializing(true);
|
|
136
136
|
setProgress(0);
|
|
137
137
|
setCurrentStep('开始初始化...');
|
|
138
|
-
|
|
138
|
+
_logger.logger.info('启动页开始执行初始化');
|
|
139
139
|
// 执行初始化,传入防抖的进度回调
|
|
140
140
|
const context = await (0, _initialization.initialization)(optionsRef.current, (progressValue, step)=>{
|
|
141
141
|
debouncedProgressUpdate(progressValue, step);
|
|
142
142
|
});
|
|
143
|
-
|
|
143
|
+
_logger.logger.info('启动页初始化完成', context);
|
|
144
144
|
// 动态调整最小显示时间(如果初始化很快,减少最小显示时间)
|
|
145
145
|
const elapsedTime = Date.now() - startTimeRef.current;
|
|
146
146
|
const dynamicMinTime = elapsedTime < 200 ? Math.min(minDisplayTimeRef.current, 300) : minDisplayTimeRef.current;
|
|
@@ -159,7 +159,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
159
159
|
// 初始化完成,调用回调
|
|
160
160
|
onCompleteRef.current(context);
|
|
161
161
|
} catch (error) {
|
|
162
|
-
|
|
162
|
+
_logger.logger.error('启动页初始化失败:', error);
|
|
163
163
|
// 设置错误状态,让 ErrorBoundary 能够捕获
|
|
164
164
|
_initialization.initializationErrorState.setError(error);
|
|
165
165
|
setCurrentStep('初始化失败,请刷新页面重试');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/splash/SplashScreen.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef, memo, useCallback } from 'react';\nimport { logger } from '../../utils';\nimport { initialization, initializationErrorState } from '../initialization';\nimport type { StartOptions, SplashScreenCustomProps } from '../types';\nimport type { InitializationContext } from '../initialization';\n\ninterface SplashScreenProps {\n options: StartOptions;\n onComplete: (context: InitializationContext) => void;\n}\n\n/**\n * 启动页组件\n * \n * 在启动页中执行初始化,并使用 Ant Design 5 的 Spin 和 Progress 组件展示启动进度\n */\nconst SplashScreen: React.FC<SplashScreenProps> = memo(({ options, onComplete }) => {\n const [progress, setProgress] = useState(0);\n const [currentStep, setCurrentStep] = useState<string>('准备初始化...');\n const [isInitializing, setIsInitializing] = useState(false);\n const [estimatedTime, setEstimatedTime] = useState<number | null>(null);\n const [isSystemDark, setIsSystemDark] = useState<boolean>(() => {\n if (typeof window === 'undefined') {\n return false;\n }\n return window.matchMedia('(prefers-color-scheme: dark)').matches;\n });\n const hasCompletedRef = useRef(false);\n const onCompleteRef = useRef(onComplete);\n const optionsRef = useRef(options);\n const startTimeRef = useRef<number>(Date.now());\n const minDisplayTimeRef = useRef<number>(options.minSplashScreenTime ?? 500); // 最小显示时间,默认 500ms\n const progressUpdateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const lastProgressRef = useRef(0);\n const progressHistoryRef = useRef<Array<{ progress: number; time: number }>>([]);\n\n // 保持引用最新\n useEffect(() => {\n onCompleteRef.current = onComplete;\n optionsRef.current = options;\n minDisplayTimeRef.current = options.minSplashScreenTime ?? 500;\n }, [onComplete, options]);\n\n // 自适应防抖进度更新函数(使用 requestAnimationFrame 优化)\n const debouncedProgressUpdate = useCallback((progressValue: number, step?: string) => {\n // 取消之前的更新\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n\n // 记录进度历史用于时间预估\n const now = Date.now();\n progressHistoryRef.current.push({ progress: progressValue, time: now });\n // 只保留最近10个记录\n if (progressHistoryRef.current.length > 10) {\n progressHistoryRef.current.shift();\n }\n\n // 计算预估时间\n if (progressHistoryRef.current.length >= 2 && progressValue > 0) {\n const history = progressHistoryRef.current;\n const first = history[0]!;\n const last = history[history.length - 1]!;\n const progressDelta = last.progress - first.progress;\n const timeDelta = last.time - first.time;\n\n if (progressDelta > 0 && timeDelta > 0) {\n const progressPerMs = progressDelta / timeDelta;\n const remainingProgress = 100 - progressValue;\n const estimatedMs = remainingProgress / progressPerMs;\n setEstimatedTime(Math.max(0, Math.round(estimatedMs)));\n }\n }\n\n // 使用 requestAnimationFrame 优化更新\n rafRef.current = requestAnimationFrame(() => {\n setProgress(progressValue);\n if (step) {\n setCurrentStep(step);\n }\n lastProgressRef.current = progressValue;\n rafRef.current = null;\n });\n }, []);\n\n useEffect(() => {\n if (hasCompletedRef.current) return;\n hasCompletedRef.current = true;\n startTimeRef.current = Date.now();\n\n const performInitialization = async () => {\n try {\n setIsInitializing(true);\n setProgress(0);\n setCurrentStep('开始初始化...');\n\n logger.info('启动页开始执行初始化');\n\n // 执行初始化,传入防抖的进度回调\n const context = await initialization(optionsRef.current, (progressValue, step) => {\n debouncedProgressUpdate(progressValue, step);\n });\n\n logger.info('启动页初始化完成', context);\n\n // 动态调整最小显示时间(如果初始化很快,减少最小显示时间)\n const elapsedTime = Date.now() - startTimeRef.current;\n const dynamicMinTime = elapsedTime < 200 ? Math.min(minDisplayTimeRef.current, 300) : minDisplayTimeRef.current;\n const remainingTime = Math.max(0, dynamicMinTime - elapsedTime);\n\n if (remainingTime > 0) {\n await new Promise((resolve) => setTimeout(resolve, remainingTime));\n }\n\n // 清理防抖定时器\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n progressUpdateTimerRef.current = null;\n }\n\n // 确保进度条显示 100%\n setProgress(100);\n setCurrentStep('初始化完成');\n\n // 初始化完成,调用回调\n onCompleteRef.current(context);\n } catch (error) {\n logger.error('启动页初始化失败:', error);\n // 设置错误状态,让 ErrorBoundary 能够捕获\n initializationErrorState.setError(error);\n setCurrentStep('初始化失败,请刷新页面重试');\n // 即使失败也调用 onComplete,让应用能够处理错误\n onCompleteRef.current({\n config: {},\n progress: 0,\n isReady: false,\n duration: 0,\n });\n } finally {\n setIsInitializing(false);\n }\n };\n\n performInitialization();\n\n // 清理函数\n return () => {\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n }\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n };\n }, [debouncedProgressUpdate]);\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const onSystemThemeChange = (event: MediaQueryListEvent) => {\n setIsSystemDark(event.matches);\n };\n\n setIsSystemDark(mediaQuery.matches);\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onSystemThemeChange);\n return () => mediaQuery.removeEventListener('change', onSystemThemeChange);\n }\n\n mediaQuery.addListener(onSystemThemeChange);\n return () => mediaQuery.removeListener(onSystemThemeChange);\n }, []);\n\n const resolvedMode = React.useMemo<'light' | 'dark'>(() => {\n const mode = optionsRef.current.theme?.mode || 'light';\n if (mode === 'system') {\n return isSystemDark ? 'dark' : 'light';\n }\n return mode === 'dark' ? 'dark' : 'light';\n }, [isSystemDark]);\n\n const palette = React.useMemo(() => {\n if (resolvedMode === 'dark') {\n return {\n background: '#0b1220',\n text: '#e2e8f0',\n subText: '#94a3b8',\n track: '#1f2937',\n spinnerTrack: '#334155',\n };\n }\n\n return {\n background: '#f5f7fb',\n text: '#51606f',\n subText: '#94a3b8',\n track: '#e9eff5',\n spinnerTrack: '#d9e2ec',\n };\n }, [resolvedMode]);\n\n // 如果提供了自定义启动屏组件,使用自定义组件\n const CustomSplashScreen = optionsRef.current.splashScreen;\n if (CustomSplashScreen) {\n const customProps: SplashScreenCustomProps = {\n progress,\n currentStep,\n isInitializing,\n };\n return <CustomSplashScreen {...customProps} />;\n }\n\n // 默认启动屏 UI\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"应用正在加载\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100vh',\n width: '100%',\n gap: 24,\n background: palette.background,\n color: palette.text,\n }}\n >\n <div\n aria-label=\"加载中\"\n style={{\n width: 42,\n height: 42,\n border: `4px solid ${palette.spinnerTrack}`,\n borderTopColor: 'var(--app-primary-color, #2f80ed)',\n borderRadius: '50%',\n animation: 'secra-spin 1s linear infinite',\n }}\n />\n <div style={{ width: '300px' }}>\n <div\n aria-label={`加载进度 ${progress}%`}\n style={{\n height: 12,\n background: palette.track,\n borderRadius: 999,\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n width: `${Math.max(0, Math.min(100, progress))}%`,\n height: '100%',\n background: 'var(--app-primary-color, #2f80ed)',\n transition: 'width 0.2s ease',\n }}\n />\n </div>\n <div style={{ marginTop: 8, textAlign: 'right', fontSize: 12, color: palette.text }}>\n {progress}%\n </div>\n </div>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{\n fontSize: 14,\n color: palette.text,\n textAlign: 'center',\n }}\n >\n {currentStep}\n {estimatedTime !== null && estimatedTime > 0 && (\n <div style={{ fontSize: 12, color: palette.subText, marginTop: 8 }}>\n 预计还需 {Math.ceil(estimatedTime / 1000)} 秒\n </div>\n )}\n </div>\n <style>\n {`@keyframes secra-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}\n </style>\n </div>\n );\n});\n\nSplashScreen.displayName = 'SplashScreen';\n\nexport { SplashScreen };\n"],"names":["SplashScreen","memo","options","onComplete","progress","setProgress","useState","currentStep","setCurrentStep","isInitializing","setIsInitializing","estimatedTime","setEstimatedTime","isSystemDark","setIsSystemDark","window","matchMedia","matches","hasCompletedRef","useRef","onCompleteRef","optionsRef","startTimeRef","Date","now","minDisplayTimeRef","minSplashScreenTime","progressUpdateTimerRef","rafRef","lastProgressRef","progressHistoryRef","useEffect","current","debouncedProgressUpdate","useCallback","progressValue","step","cancelAnimationFrame","push","time","length","shift","history","first","last","progressDelta","timeDelta","progressPerMs","remainingProgress","estimatedMs","Math","max","round","requestAnimationFrame","performInitialization","logger","info","context","initialization","elapsedTime","dynamicMinTime","min","remainingTime","Promise","resolve","setTimeout","clearTimeout","error","initializationErrorState","setError","config","isReady","duration","mediaQuery","onSystemThemeChange","event","addEventListener","removeEventListener","addListener","removeListener","resolvedMode","React","useMemo","mode","theme","palette","background","text","subText","track","spinnerTrack","CustomSplashScreen","splashScreen","customProps","div","role","aria-live","aria-label","style","display","flexDirection","alignItems","justifyContent","height","width","gap","color","border","borderTopColor","borderRadius","animation","overflow","transition","marginTop","textAlign","fontSize","ceil","displayName"],"mappings":";;;;+BAsSSA;;;eAAAA;;;;+DAtS6D;uBAC/C;gCACkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASzD;;;;CAIC,GACD,MAAMA,6BAA4CC,IAAAA,WAAI,EAAC,CAAC,EAAEC,OAAO,EAAEC,UAAU,EAAE;IAC7E,MAAM,CAACC,UAAUC,YAAY,GAAGC,IAAAA,eAAQ,EAAC;IACzC,MAAM,CAACC,aAAaC,eAAe,GAAGF,IAAAA,eAAQ,EAAS;IACvD,MAAM,CAACG,gBAAgBC,kBAAkB,GAAGJ,IAAAA,eAAQ,EAAC;IACrD,MAAM,CAACK,eAAeC,iBAAiB,GAAGN,IAAAA,eAAQ,EAAgB;IAClE,MAAM,CAACO,cAAcC,gBAAgB,GAAGR,IAAAA,eAAQ,EAAU;QACxD,IAAI,OAAOS,WAAW,aAAa;YACjC,OAAO;QACT;QACA,OAAOA,OAAOC,UAAU,CAAC,gCAAgCC,OAAO;IAClE;IACA,MAAMC,kBAAkBC,IAAAA,aAAM,EAAC;IAC/B,MAAMC,gBAAgBD,IAAAA,aAAM,EAAChB;IAC7B,MAAMkB,aAAaF,IAAAA,aAAM,EAACjB;IAC1B,MAAMoB,eAAeH,IAAAA,aAAM,EAASI,KAAKC,GAAG;IAC5C,MAAMC,oBAAoBN,IAAAA,aAAM,EAASjB,QAAQwB,mBAAmB,IAAI,MAAM,kBAAkB;IAChG,MAAMC,yBAAyBR,IAAAA,aAAM,EAAuC;IAC5E,MAAMS,SAAST,IAAAA,aAAM,EAAgB;IACrC,MAAMU,kBAAkBV,IAAAA,aAAM,EAAC;IAC/B,MAAMW,qBAAqBX,IAAAA,aAAM,EAA4C,EAAE;IAE/E,SAAS;IACTY,IAAAA,gBAAS,EAAC;QACRX,cAAcY,OAAO,GAAG7B;QACxBkB,WAAWW,OAAO,GAAG9B;QACrBuB,kBAAkBO,OAAO,GAAG9B,QAAQwB,mBAAmB,IAAI;IAC7D,GAAG;QAACvB;QAAYD;KAAQ;IAExB,2CAA2C;IAC3C,MAAM+B,0BAA0BC,IAAAA,kBAAW,EAAC,CAACC,eAAuBC;QAClE,UAAU;QACV,IAAIR,OAAOI,OAAO,KAAK,MAAM;YAC3BK,qBAAqBT,OAAOI,OAAO;QACrC;QAEA,eAAe;QACf,MAAMR,MAAMD,KAAKC,GAAG;QACpBM,mBAAmBE,OAAO,CAACM,IAAI,CAAC;YAAElC,UAAU+B;YAAeI,MAAMf;QAAI;QACrE,aAAa;QACb,IAAIM,mBAAmBE,OAAO,CAACQ,MAAM,GAAG,IAAI;YAC1CV,mBAAmBE,OAAO,CAACS,KAAK;QAClC;QAEA,SAAS;QACT,IAAIX,mBAAmBE,OAAO,CAACQ,MAAM,IAAI,KAAKL,gBAAgB,GAAG;YAC/D,MAAMO,UAAUZ,mBAAmBE,OAAO;YAC1C,MAAMW,QAAQD,OAAO,CAAC,EAAE;YACxB,MAAME,OAAOF,OAAO,CAACA,QAAQF,MAAM,GAAG,EAAE;YACxC,MAAMK,gBAAgBD,KAAKxC,QAAQ,GAAGuC,MAAMvC,QAAQ;YACpD,MAAM0C,YAAYF,KAAKL,IAAI,GAAGI,MAAMJ,IAAI;YAExC,IAAIM,gBAAgB,KAAKC,YAAY,GAAG;gBACtC,MAAMC,gBAAgBF,gBAAgBC;gBACtC,MAAME,oBAAoB,MAAMb;gBAChC,MAAMc,cAAcD,oBAAoBD;gBACxCnC,iBAAiBsC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,KAAK,CAACH;YAC1C;QACF;QAEA,gCAAgC;QAChCrB,OAAOI,OAAO,GAAGqB,sBAAsB;YACrChD,YAAY8B;YACZ,IAAIC,MAAM;gBACR5B,eAAe4B;YACjB;YACAP,gBAAgBG,OAAO,GAAGG;YAC1BP,OAAOI,OAAO,GAAG;QACnB;IACF,GAAG,EAAE;IAELD,IAAAA,gBAAS,EAAC;QACR,IAAIb,gBAAgBc,OAAO,EAAE;QAC7Bd,gBAAgBc,OAAO,GAAG;QAC1BV,aAAaU,OAAO,GAAGT,KAAKC,GAAG;QAE/B,MAAM8B,wBAAwB;YAC5B,IAAI;gBACF5C,kBAAkB;gBAClBL,YAAY;gBACZG,eAAe;gBAEf+C,aAAM,CAACC,IAAI,CAAC;gBAEZ,kBAAkB;gBAClB,MAAMC,UAAU,MAAMC,IAAAA,8BAAc,EAACrC,WAAWW,OAAO,EAAE,CAACG,eAAeC;oBACvEH,wBAAwBE,eAAeC;gBACzC;gBAEAmB,aAAM,CAACC,IAAI,CAAC,YAAYC;gBAExB,+BAA+B;gBAC/B,MAAME,cAAcpC,KAAKC,GAAG,KAAKF,aAAaU,OAAO;gBACrD,MAAM4B,iBAAiBD,cAAc,MAAMT,KAAKW,GAAG,CAACpC,kBAAkBO,OAAO,EAAE,OAAOP,kBAAkBO,OAAO;gBAC/G,MAAM8B,gBAAgBZ,KAAKC,GAAG,CAAC,GAAGS,iBAAiBD;gBAEnD,IAAIG,gBAAgB,GAAG;oBACrB,MAAM,IAAIC,QAAQ,CAACC,UAAYC,WAAWD,SAASF;gBACrD;gBAEA,UAAU;gBACV,IAAInC,uBAAuBK,OAAO,EAAE;oBAClCkC,aAAavC,uBAAuBK,OAAO;oBAC3CL,uBAAuBK,OAAO,GAAG;gBACnC;gBAEA,eAAe;gBACf3B,YAAY;gBACZG,eAAe;gBAEf,aAAa;gBACbY,cAAcY,OAAO,CAACyB;YACxB,EAAE,OAAOU,OAAO;gBACdZ,aAAM,CAACY,KAAK,CAAC,aAAaA;gBAC1B,8BAA8B;gBAC9BC,wCAAwB,CAACC,QAAQ,CAACF;gBAClC3D,eAAe;gBACf,+BAA+B;gBAC/BY,cAAcY,OAAO,CAAC;oBACpBsC,QAAQ,CAAC;oBACTlE,UAAU;oBACVmE,SAAS;oBACTC,UAAU;gBACZ;YACF,SAAU;gBACR9D,kBAAkB;YACpB;QACF;QAEA4C;QAEA,OAAO;QACP,OAAO;YACL,IAAI3B,uBAAuBK,OAAO,EAAE;gBAClCkC,aAAavC,uBAAuBK,OAAO;YAC7C;YACA,IAAIJ,OAAOI,OAAO,KAAK,MAAM;gBAC3BK,qBAAqBT,OAAOI,OAAO;YACrC;QACF;IACF,GAAG;QAACC;KAAwB;IAE5BF,IAAAA,gBAAS,EAAC;QACR,IAAI,OAAOhB,WAAW,aAAa;YACjC;QACF;QAEA,MAAM0D,aAAa1D,OAAOC,UAAU,CAAC;QACrC,MAAM0D,sBAAsB,CAACC;YAC3B7D,gBAAgB6D,MAAM1D,OAAO;QAC/B;QAEAH,gBAAgB2D,WAAWxD,OAAO;QAElC,IAAI,OAAOwD,WAAWG,gBAAgB,KAAK,YAAY;YACrDH,WAAWG,gBAAgB,CAAC,UAAUF;YACtC,OAAO,IAAMD,WAAWI,mBAAmB,CAAC,UAAUH;QACxD;QAEAD,WAAWK,WAAW,CAACJ;QACvB,OAAO,IAAMD,WAAWM,cAAc,CAACL;IACzC,GAAG,EAAE;IAEL,MAAMM,eAAeC,cAAK,CAACC,OAAO,CAAmB;QACnD,MAAMC,OAAO9D,WAAWW,OAAO,CAACoD,KAAK,EAAED,QAAQ;QAC/C,IAAIA,SAAS,UAAU;YACrB,OAAOtE,eAAe,SAAS;QACjC;QACA,OAAOsE,SAAS,SAAS,SAAS;IACpC,GAAG;QAACtE;KAAa;IAEjB,MAAMwE,UAAUJ,cAAK,CAACC,OAAO,CAAC;QAC5B,IAAIF,iBAAiB,QAAQ;YAC3B,OAAO;gBACLM,YAAY;gBACZC,MAAM;gBACNC,SAAS;gBACTC,OAAO;gBACPC,cAAc;YAChB;QACF;QAEA,OAAO;YACLJ,YAAY;YACZC,MAAM;YACNC,SAAS;YACTC,OAAO;YACPC,cAAc;QAChB;IACF,GAAG;QAACV;KAAa;IAEjB,wBAAwB;IACxB,MAAMW,qBAAqBtE,WAAWW,OAAO,CAAC4D,YAAY;IAC1D,IAAID,oBAAoB;QACtB,MAAME,cAAuC;YAC3CzF;YACAG;YACAE;QACF;QACA,qBAAO,qBAACkF;YAAoB,GAAGE,WAAW;;IAC5C;IAEA,WAAW;IACX,qBACE,sBAACC;QACCC,MAAK;QACLC,aAAU;QACVC,cAAW;QACXC,OAAO;YACLC,SAAS;YACTC,eAAe;YACfC,YAAY;YACZC,gBAAgB;YAChBC,QAAQ;YACRC,OAAO;YACPC,KAAK;YACLnB,YAAYD,QAAQC,UAAU;YAC9BoB,OAAOrB,QAAQE,IAAI;QACrB;;0BAEA,qBAACO;gBACCG,cAAW;gBACXC,OAAO;oBACLM,OAAO;oBACPD,QAAQ;oBACRI,QAAQ,CAAC,UAAU,EAAEtB,QAAQK,YAAY,EAAE;oBAC3CkB,gBAAgB;oBAChBC,cAAc;oBACdC,WAAW;gBACb;;0BAEF,sBAAChB;gBAAII,OAAO;oBAAEM,OAAO;gBAAQ;;kCAC3B,qBAACV;wBACCG,cAAY,CAAC,KAAK,EAAE7F,SAAS,CAAC,CAAC;wBAC/B8F,OAAO;4BACLK,QAAQ;4BACRjB,YAAYD,QAAQI,KAAK;4BACzBoB,cAAc;4BACdE,UAAU;wBACZ;kCAEA,cAAA,qBAACjB;4BACCI,OAAO;gCACLM,OAAO,GAAGtD,KAAKC,GAAG,CAAC,GAAGD,KAAKW,GAAG,CAAC,KAAKzD,WAAW,CAAC,CAAC;gCACjDmG,QAAQ;gCACRjB,YAAY;gCACZ0B,YAAY;4BACd;;;kCAGJ,sBAAClB;wBAAII,OAAO;4BAAEe,WAAW;4BAAGC,WAAW;4BAASC,UAAU;4BAAIT,OAAOrB,QAAQE,IAAI;wBAAC;;4BAC/EnF;4BAAS;;;;;0BAGd,sBAAC0F;gBACCC,MAAK;gBACLC,aAAU;gBACVE,OAAO;oBACLiB,UAAU;oBACVT,OAAOrB,QAAQE,IAAI;oBACnB2B,WAAW;gBACb;;oBAEC3G;oBACAI,kBAAkB,QAAQA,gBAAgB,mBACzC,sBAACmF;wBAAII,OAAO;4BAAEiB,UAAU;4BAAIT,OAAOrB,QAAQG,OAAO;4BAAEyB,WAAW;wBAAE;;4BAAG;4BAC5D/D,KAAKkE,IAAI,CAACzG,gBAAgB;4BAAM;;;;;0BAI5C,qBAACuF;0BACE,CAAC,6FAA6F,CAAC;;;;AAIxG;AAEAlG,aAAaqH,WAAW,GAAG"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/splash/SplashScreen.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef, memo, useCallback } from 'react';\nimport { logger } from '@vlian/logger';\nimport { initialization, initializationErrorState } from '../initialization';\nimport type { StartOptions, SplashScreenCustomProps } from '../types';\nimport type { InitializationContext } from '../initialization';\n\ninterface SplashScreenProps {\n options: StartOptions;\n onComplete: (context: InitializationContext) => void;\n}\n\n/**\n * 启动页组件\n * \n * 在启动页中执行初始化,并使用 Ant Design 5 的 Spin 和 Progress 组件展示启动进度\n */\nconst SplashScreen: React.FC<SplashScreenProps> = memo(({ options, onComplete }) => {\n const [progress, setProgress] = useState(0);\n const [currentStep, setCurrentStep] = useState<string>('准备初始化...');\n const [isInitializing, setIsInitializing] = useState(false);\n const [estimatedTime, setEstimatedTime] = useState<number | null>(null);\n const [isSystemDark, setIsSystemDark] = useState<boolean>(() => {\n if (typeof window === 'undefined') {\n return false;\n }\n return window.matchMedia('(prefers-color-scheme: dark)').matches;\n });\n const hasCompletedRef = useRef(false);\n const onCompleteRef = useRef(onComplete);\n const optionsRef = useRef(options);\n const startTimeRef = useRef<number>(Date.now());\n const minDisplayTimeRef = useRef<number>(options.minSplashScreenTime ?? 500); // 最小显示时间,默认 500ms\n const progressUpdateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const lastProgressRef = useRef(0);\n const progressHistoryRef = useRef<Array<{ progress: number; time: number }>>([]);\n\n // 保持引用最新\n useEffect(() => {\n onCompleteRef.current = onComplete;\n optionsRef.current = options;\n minDisplayTimeRef.current = options.minSplashScreenTime ?? 500;\n }, [onComplete, options]);\n\n // 自适应防抖进度更新函数(使用 requestAnimationFrame 优化)\n const debouncedProgressUpdate = useCallback((progressValue: number, step?: string) => {\n // 取消之前的更新\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n\n // 记录进度历史用于时间预估\n const now = Date.now();\n progressHistoryRef.current.push({ progress: progressValue, time: now });\n // 只保留最近10个记录\n if (progressHistoryRef.current.length > 10) {\n progressHistoryRef.current.shift();\n }\n\n // 计算预估时间\n if (progressHistoryRef.current.length >= 2 && progressValue > 0) {\n const history = progressHistoryRef.current;\n const first = history[0]!;\n const last = history[history.length - 1]!;\n const progressDelta = last.progress - first.progress;\n const timeDelta = last.time - first.time;\n\n if (progressDelta > 0 && timeDelta > 0) {\n const progressPerMs = progressDelta / timeDelta;\n const remainingProgress = 100 - progressValue;\n const estimatedMs = remainingProgress / progressPerMs;\n setEstimatedTime(Math.max(0, Math.round(estimatedMs)));\n }\n }\n\n // 使用 requestAnimationFrame 优化更新\n rafRef.current = requestAnimationFrame(() => {\n setProgress(progressValue);\n if (step) {\n setCurrentStep(step);\n }\n lastProgressRef.current = progressValue;\n rafRef.current = null;\n });\n }, []);\n\n useEffect(() => {\n if (hasCompletedRef.current) return;\n hasCompletedRef.current = true;\n startTimeRef.current = Date.now();\n\n const performInitialization = async () => {\n try {\n setIsInitializing(true);\n setProgress(0);\n setCurrentStep('开始初始化...');\n\n logger.info('启动页开始执行初始化');\n\n // 执行初始化,传入防抖的进度回调\n const context = await initialization(optionsRef.current, (progressValue, step) => {\n debouncedProgressUpdate(progressValue, step);\n });\n\n logger.info('启动页初始化完成', context);\n\n // 动态调整最小显示时间(如果初始化很快,减少最小显示时间)\n const elapsedTime = Date.now() - startTimeRef.current;\n const dynamicMinTime = elapsedTime < 200 ? Math.min(minDisplayTimeRef.current, 300) : minDisplayTimeRef.current;\n const remainingTime = Math.max(0, dynamicMinTime - elapsedTime);\n\n if (remainingTime > 0) {\n await new Promise((resolve) => setTimeout(resolve, remainingTime));\n }\n\n // 清理防抖定时器\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n progressUpdateTimerRef.current = null;\n }\n\n // 确保进度条显示 100%\n setProgress(100);\n setCurrentStep('初始化完成');\n\n // 初始化完成,调用回调\n onCompleteRef.current(context);\n } catch (error) {\n logger.error('启动页初始化失败:', error);\n // 设置错误状态,让 ErrorBoundary 能够捕获\n initializationErrorState.setError(error);\n setCurrentStep('初始化失败,请刷新页面重试');\n // 即使失败也调用 onComplete,让应用能够处理错误\n onCompleteRef.current({\n config: {},\n progress: 0,\n isReady: false,\n duration: 0,\n });\n } finally {\n setIsInitializing(false);\n }\n };\n\n performInitialization();\n\n // 清理函数\n return () => {\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n }\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n };\n }, [debouncedProgressUpdate]);\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const onSystemThemeChange = (event: MediaQueryListEvent) => {\n setIsSystemDark(event.matches);\n };\n\n setIsSystemDark(mediaQuery.matches);\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onSystemThemeChange);\n return () => mediaQuery.removeEventListener('change', onSystemThemeChange);\n }\n\n mediaQuery.addListener(onSystemThemeChange);\n return () => mediaQuery.removeListener(onSystemThemeChange);\n }, []);\n\n const resolvedMode = React.useMemo<'light' | 'dark'>(() => {\n const mode = optionsRef.current.theme?.mode || 'light';\n if (mode === 'system') {\n return isSystemDark ? 'dark' : 'light';\n }\n return mode === 'dark' ? 'dark' : 'light';\n }, [isSystemDark]);\n\n const palette = React.useMemo(() => {\n if (resolvedMode === 'dark') {\n return {\n background: '#0b1220',\n text: '#e2e8f0',\n subText: '#94a3b8',\n track: '#1f2937',\n spinnerTrack: '#334155',\n };\n }\n\n return {\n background: '#f5f7fb',\n text: '#51606f',\n subText: '#94a3b8',\n track: '#e9eff5',\n spinnerTrack: '#d9e2ec',\n };\n }, [resolvedMode]);\n\n // 如果提供了自定义启动屏组件,使用自定义组件\n const CustomSplashScreen = optionsRef.current.splashScreen;\n if (CustomSplashScreen) {\n const customProps: SplashScreenCustomProps = {\n progress,\n currentStep,\n isInitializing,\n };\n return <CustomSplashScreen {...customProps} />;\n }\n\n // 默认启动屏 UI\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"应用正在加载\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100vh',\n width: '100%',\n gap: 24,\n background: palette.background,\n color: palette.text,\n }}\n >\n <div\n aria-label=\"加载中\"\n style={{\n width: 42,\n height: 42,\n border: `4px solid ${palette.spinnerTrack}`,\n borderTopColor: 'var(--app-primary-color, #2f80ed)',\n borderRadius: '50%',\n animation: 'secra-spin 1s linear infinite',\n }}\n />\n <div style={{ width: '300px' }}>\n <div\n aria-label={`加载进度 ${progress}%`}\n style={{\n height: 12,\n background: palette.track,\n borderRadius: 999,\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n width: `${Math.max(0, Math.min(100, progress))}%`,\n height: '100%',\n background: 'var(--app-primary-color, #2f80ed)',\n transition: 'width 0.2s ease',\n }}\n />\n </div>\n <div style={{ marginTop: 8, textAlign: 'right', fontSize: 12, color: palette.text }}>\n {progress}%\n </div>\n </div>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{\n fontSize: 14,\n color: palette.text,\n textAlign: 'center',\n }}\n >\n {currentStep}\n {estimatedTime !== null && estimatedTime > 0 && (\n <div style={{ fontSize: 12, color: palette.subText, marginTop: 8 }}>\n 预计还需 {Math.ceil(estimatedTime / 1000)} 秒\n </div>\n )}\n </div>\n <style>\n {`@keyframes secra-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}\n </style>\n </div>\n );\n});\n\nSplashScreen.displayName = 'SplashScreen';\n\nexport { SplashScreen };\n"],"names":["SplashScreen","memo","options","onComplete","progress","setProgress","useState","currentStep","setCurrentStep","isInitializing","setIsInitializing","estimatedTime","setEstimatedTime","isSystemDark","setIsSystemDark","window","matchMedia","matches","hasCompletedRef","useRef","onCompleteRef","optionsRef","startTimeRef","Date","now","minDisplayTimeRef","minSplashScreenTime","progressUpdateTimerRef","rafRef","lastProgressRef","progressHistoryRef","useEffect","current","debouncedProgressUpdate","useCallback","progressValue","step","cancelAnimationFrame","push","time","length","shift","history","first","last","progressDelta","timeDelta","progressPerMs","remainingProgress","estimatedMs","Math","max","round","requestAnimationFrame","performInitialization","logger","info","context","initialization","elapsedTime","dynamicMinTime","min","remainingTime","Promise","resolve","setTimeout","clearTimeout","error","initializationErrorState","setError","config","isReady","duration","mediaQuery","onSystemThemeChange","event","addEventListener","removeEventListener","addListener","removeListener","resolvedMode","React","useMemo","mode","theme","palette","background","text","subText","track","spinnerTrack","CustomSplashScreen","splashScreen","customProps","div","role","aria-live","aria-label","style","display","flexDirection","alignItems","justifyContent","height","width","gap","color","border","borderTopColor","borderRadius","animation","overflow","transition","marginTop","textAlign","fontSize","ceil","displayName"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useEffect, useState, useRef, memo, useCallback } from "react";
|
|
3
|
-
import { logger } from "
|
|
3
|
+
import { logger } from "@vlian/logger";
|
|
4
4
|
import { initialization, initializationErrorState } from "../initialization";
|
|
5
5
|
/**
|
|
6
6
|
* 启动页组件
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/splash/SplashScreen.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef, memo, useCallback } from 'react';\nimport { logger } from '../../utils';\nimport { initialization, initializationErrorState } from '../initialization';\nimport type { StartOptions, SplashScreenCustomProps } from '../types';\nimport type { InitializationContext } from '../initialization';\n\ninterface SplashScreenProps {\n options: StartOptions;\n onComplete: (context: InitializationContext) => void;\n}\n\n/**\n * 启动页组件\n * \n * 在启动页中执行初始化,并使用 Ant Design 5 的 Spin 和 Progress 组件展示启动进度\n */\nconst SplashScreen: React.FC<SplashScreenProps> = memo(({ options, onComplete }) => {\n const [progress, setProgress] = useState(0);\n const [currentStep, setCurrentStep] = useState<string>('准备初始化...');\n const [isInitializing, setIsInitializing] = useState(false);\n const [estimatedTime, setEstimatedTime] = useState<number | null>(null);\n const [isSystemDark, setIsSystemDark] = useState<boolean>(() => {\n if (typeof window === 'undefined') {\n return false;\n }\n return window.matchMedia('(prefers-color-scheme: dark)').matches;\n });\n const hasCompletedRef = useRef(false);\n const onCompleteRef = useRef(onComplete);\n const optionsRef = useRef(options);\n const startTimeRef = useRef<number>(Date.now());\n const minDisplayTimeRef = useRef<number>(options.minSplashScreenTime ?? 500); // 最小显示时间,默认 500ms\n const progressUpdateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const lastProgressRef = useRef(0);\n const progressHistoryRef = useRef<Array<{ progress: number; time: number }>>([]);\n\n // 保持引用最新\n useEffect(() => {\n onCompleteRef.current = onComplete;\n optionsRef.current = options;\n minDisplayTimeRef.current = options.minSplashScreenTime ?? 500;\n }, [onComplete, options]);\n\n // 自适应防抖进度更新函数(使用 requestAnimationFrame 优化)\n const debouncedProgressUpdate = useCallback((progressValue: number, step?: string) => {\n // 取消之前的更新\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n\n // 记录进度历史用于时间预估\n const now = Date.now();\n progressHistoryRef.current.push({ progress: progressValue, time: now });\n // 只保留最近10个记录\n if (progressHistoryRef.current.length > 10) {\n progressHistoryRef.current.shift();\n }\n\n // 计算预估时间\n if (progressHistoryRef.current.length >= 2 && progressValue > 0) {\n const history = progressHistoryRef.current;\n const first = history[0]!;\n const last = history[history.length - 1]!;\n const progressDelta = last.progress - first.progress;\n const timeDelta = last.time - first.time;\n\n if (progressDelta > 0 && timeDelta > 0) {\n const progressPerMs = progressDelta / timeDelta;\n const remainingProgress = 100 - progressValue;\n const estimatedMs = remainingProgress / progressPerMs;\n setEstimatedTime(Math.max(0, Math.round(estimatedMs)));\n }\n }\n\n // 使用 requestAnimationFrame 优化更新\n rafRef.current = requestAnimationFrame(() => {\n setProgress(progressValue);\n if (step) {\n setCurrentStep(step);\n }\n lastProgressRef.current = progressValue;\n rafRef.current = null;\n });\n }, []);\n\n useEffect(() => {\n if (hasCompletedRef.current) return;\n hasCompletedRef.current = true;\n startTimeRef.current = Date.now();\n\n const performInitialization = async () => {\n try {\n setIsInitializing(true);\n setProgress(0);\n setCurrentStep('开始初始化...');\n\n logger.info('启动页开始执行初始化');\n\n // 执行初始化,传入防抖的进度回调\n const context = await initialization(optionsRef.current, (progressValue, step) => {\n debouncedProgressUpdate(progressValue, step);\n });\n\n logger.info('启动页初始化完成', context);\n\n // 动态调整最小显示时间(如果初始化很快,减少最小显示时间)\n const elapsedTime = Date.now() - startTimeRef.current;\n const dynamicMinTime = elapsedTime < 200 ? Math.min(minDisplayTimeRef.current, 300) : minDisplayTimeRef.current;\n const remainingTime = Math.max(0, dynamicMinTime - elapsedTime);\n\n if (remainingTime > 0) {\n await new Promise((resolve) => setTimeout(resolve, remainingTime));\n }\n\n // 清理防抖定时器\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n progressUpdateTimerRef.current = null;\n }\n\n // 确保进度条显示 100%\n setProgress(100);\n setCurrentStep('初始化完成');\n\n // 初始化完成,调用回调\n onCompleteRef.current(context);\n } catch (error) {\n logger.error('启动页初始化失败:', error);\n // 设置错误状态,让 ErrorBoundary 能够捕获\n initializationErrorState.setError(error);\n setCurrentStep('初始化失败,请刷新页面重试');\n // 即使失败也调用 onComplete,让应用能够处理错误\n onCompleteRef.current({\n config: {},\n progress: 0,\n isReady: false,\n duration: 0,\n });\n } finally {\n setIsInitializing(false);\n }\n };\n\n performInitialization();\n\n // 清理函数\n return () => {\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n }\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n };\n }, [debouncedProgressUpdate]);\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const onSystemThemeChange = (event: MediaQueryListEvent) => {\n setIsSystemDark(event.matches);\n };\n\n setIsSystemDark(mediaQuery.matches);\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onSystemThemeChange);\n return () => mediaQuery.removeEventListener('change', onSystemThemeChange);\n }\n\n mediaQuery.addListener(onSystemThemeChange);\n return () => mediaQuery.removeListener(onSystemThemeChange);\n }, []);\n\n const resolvedMode = React.useMemo<'light' | 'dark'>(() => {\n const mode = optionsRef.current.theme?.mode || 'light';\n if (mode === 'system') {\n return isSystemDark ? 'dark' : 'light';\n }\n return mode === 'dark' ? 'dark' : 'light';\n }, [isSystemDark]);\n\n const palette = React.useMemo(() => {\n if (resolvedMode === 'dark') {\n return {\n background: '#0b1220',\n text: '#e2e8f0',\n subText: '#94a3b8',\n track: '#1f2937',\n spinnerTrack: '#334155',\n };\n }\n\n return {\n background: '#f5f7fb',\n text: '#51606f',\n subText: '#94a3b8',\n track: '#e9eff5',\n spinnerTrack: '#d9e2ec',\n };\n }, [resolvedMode]);\n\n // 如果提供了自定义启动屏组件,使用自定义组件\n const CustomSplashScreen = optionsRef.current.splashScreen;\n if (CustomSplashScreen) {\n const customProps: SplashScreenCustomProps = {\n progress,\n currentStep,\n isInitializing,\n };\n return <CustomSplashScreen {...customProps} />;\n }\n\n // 默认启动屏 UI\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"应用正在加载\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100vh',\n width: '100%',\n gap: 24,\n background: palette.background,\n color: palette.text,\n }}\n >\n <div\n aria-label=\"加载中\"\n style={{\n width: 42,\n height: 42,\n border: `4px solid ${palette.spinnerTrack}`,\n borderTopColor: 'var(--app-primary-color, #2f80ed)',\n borderRadius: '50%',\n animation: 'secra-spin 1s linear infinite',\n }}\n />\n <div style={{ width: '300px' }}>\n <div\n aria-label={`加载进度 ${progress}%`}\n style={{\n height: 12,\n background: palette.track,\n borderRadius: 999,\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n width: `${Math.max(0, Math.min(100, progress))}%`,\n height: '100%',\n background: 'var(--app-primary-color, #2f80ed)',\n transition: 'width 0.2s ease',\n }}\n />\n </div>\n <div style={{ marginTop: 8, textAlign: 'right', fontSize: 12, color: palette.text }}>\n {progress}%\n </div>\n </div>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{\n fontSize: 14,\n color: palette.text,\n textAlign: 'center',\n }}\n >\n {currentStep}\n {estimatedTime !== null && estimatedTime > 0 && (\n <div style={{ fontSize: 12, color: palette.subText, marginTop: 8 }}>\n 预计还需 {Math.ceil(estimatedTime / 1000)} 秒\n </div>\n )}\n </div>\n <style>\n {`@keyframes secra-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}\n </style>\n </div>\n );\n});\n\nSplashScreen.displayName = 'SplashScreen';\n\nexport { SplashScreen };\n"],"names":["React","useEffect","useState","useRef","memo","useCallback","logger","initialization","initializationErrorState","SplashScreen","options","onComplete","progress","setProgress","currentStep","setCurrentStep","isInitializing","setIsInitializing","estimatedTime","setEstimatedTime","isSystemDark","setIsSystemDark","window","matchMedia","matches","hasCompletedRef","onCompleteRef","optionsRef","startTimeRef","Date","now","minDisplayTimeRef","minSplashScreenTime","progressUpdateTimerRef","rafRef","lastProgressRef","progressHistoryRef","current","debouncedProgressUpdate","progressValue","step","cancelAnimationFrame","push","time","length","shift","history","first","last","progressDelta","timeDelta","progressPerMs","remainingProgress","estimatedMs","Math","max","round","requestAnimationFrame","performInitialization","info","context","elapsedTime","dynamicMinTime","min","remainingTime","Promise","resolve","setTimeout","clearTimeout","error","setError","config","isReady","duration","mediaQuery","onSystemThemeChange","event","addEventListener","removeEventListener","addListener","removeListener","resolvedMode","useMemo","mode","theme","palette","background","text","subText","track","spinnerTrack","CustomSplashScreen","splashScreen","customProps","div","role","aria-live","aria-label","style","display","flexDirection","alignItems","justifyContent","height","width","gap","color","border","borderTopColor","borderRadius","animation","overflow","transition","marginTop","textAlign","fontSize","ceil","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/splash/SplashScreen.tsx"],"sourcesContent":["import React, { useEffect, useState, useRef, memo, useCallback } from 'react';\nimport { logger } from '@vlian/logger';\nimport { initialization, initializationErrorState } from '../initialization';\nimport type { StartOptions, SplashScreenCustomProps } from '../types';\nimport type { InitializationContext } from '../initialization';\n\ninterface SplashScreenProps {\n options: StartOptions;\n onComplete: (context: InitializationContext) => void;\n}\n\n/**\n * 启动页组件\n * \n * 在启动页中执行初始化,并使用 Ant Design 5 的 Spin 和 Progress 组件展示启动进度\n */\nconst SplashScreen: React.FC<SplashScreenProps> = memo(({ options, onComplete }) => {\n const [progress, setProgress] = useState(0);\n const [currentStep, setCurrentStep] = useState<string>('准备初始化...');\n const [isInitializing, setIsInitializing] = useState(false);\n const [estimatedTime, setEstimatedTime] = useState<number | null>(null);\n const [isSystemDark, setIsSystemDark] = useState<boolean>(() => {\n if (typeof window === 'undefined') {\n return false;\n }\n return window.matchMedia('(prefers-color-scheme: dark)').matches;\n });\n const hasCompletedRef = useRef(false);\n const onCompleteRef = useRef(onComplete);\n const optionsRef = useRef(options);\n const startTimeRef = useRef<number>(Date.now());\n const minDisplayTimeRef = useRef<number>(options.minSplashScreenTime ?? 500); // 最小显示时间,默认 500ms\n const progressUpdateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const rafRef = useRef<number | null>(null);\n const lastProgressRef = useRef(0);\n const progressHistoryRef = useRef<Array<{ progress: number; time: number }>>([]);\n\n // 保持引用最新\n useEffect(() => {\n onCompleteRef.current = onComplete;\n optionsRef.current = options;\n minDisplayTimeRef.current = options.minSplashScreenTime ?? 500;\n }, [onComplete, options]);\n\n // 自适应防抖进度更新函数(使用 requestAnimationFrame 优化)\n const debouncedProgressUpdate = useCallback((progressValue: number, step?: string) => {\n // 取消之前的更新\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n\n // 记录进度历史用于时间预估\n const now = Date.now();\n progressHistoryRef.current.push({ progress: progressValue, time: now });\n // 只保留最近10个记录\n if (progressHistoryRef.current.length > 10) {\n progressHistoryRef.current.shift();\n }\n\n // 计算预估时间\n if (progressHistoryRef.current.length >= 2 && progressValue > 0) {\n const history = progressHistoryRef.current;\n const first = history[0]!;\n const last = history[history.length - 1]!;\n const progressDelta = last.progress - first.progress;\n const timeDelta = last.time - first.time;\n\n if (progressDelta > 0 && timeDelta > 0) {\n const progressPerMs = progressDelta / timeDelta;\n const remainingProgress = 100 - progressValue;\n const estimatedMs = remainingProgress / progressPerMs;\n setEstimatedTime(Math.max(0, Math.round(estimatedMs)));\n }\n }\n\n // 使用 requestAnimationFrame 优化更新\n rafRef.current = requestAnimationFrame(() => {\n setProgress(progressValue);\n if (step) {\n setCurrentStep(step);\n }\n lastProgressRef.current = progressValue;\n rafRef.current = null;\n });\n }, []);\n\n useEffect(() => {\n if (hasCompletedRef.current) return;\n hasCompletedRef.current = true;\n startTimeRef.current = Date.now();\n\n const performInitialization = async () => {\n try {\n setIsInitializing(true);\n setProgress(0);\n setCurrentStep('开始初始化...');\n\n logger.info('启动页开始执行初始化');\n\n // 执行初始化,传入防抖的进度回调\n const context = await initialization(optionsRef.current, (progressValue, step) => {\n debouncedProgressUpdate(progressValue, step);\n });\n\n logger.info('启动页初始化完成', context);\n\n // 动态调整最小显示时间(如果初始化很快,减少最小显示时间)\n const elapsedTime = Date.now() - startTimeRef.current;\n const dynamicMinTime = elapsedTime < 200 ? Math.min(minDisplayTimeRef.current, 300) : minDisplayTimeRef.current;\n const remainingTime = Math.max(0, dynamicMinTime - elapsedTime);\n\n if (remainingTime > 0) {\n await new Promise((resolve) => setTimeout(resolve, remainingTime));\n }\n\n // 清理防抖定时器\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n progressUpdateTimerRef.current = null;\n }\n\n // 确保进度条显示 100%\n setProgress(100);\n setCurrentStep('初始化完成');\n\n // 初始化完成,调用回调\n onCompleteRef.current(context);\n } catch (error) {\n logger.error('启动页初始化失败:', error);\n // 设置错误状态,让 ErrorBoundary 能够捕获\n initializationErrorState.setError(error);\n setCurrentStep('初始化失败,请刷新页面重试');\n // 即使失败也调用 onComplete,让应用能够处理错误\n onCompleteRef.current({\n config: {},\n progress: 0,\n isReady: false,\n duration: 0,\n });\n } finally {\n setIsInitializing(false);\n }\n };\n\n performInitialization();\n\n // 清理函数\n return () => {\n if (progressUpdateTimerRef.current) {\n clearTimeout(progressUpdateTimerRef.current);\n }\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n }\n };\n }, [debouncedProgressUpdate]);\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const onSystemThemeChange = (event: MediaQueryListEvent) => {\n setIsSystemDark(event.matches);\n };\n\n setIsSystemDark(mediaQuery.matches);\n\n if (typeof mediaQuery.addEventListener === 'function') {\n mediaQuery.addEventListener('change', onSystemThemeChange);\n return () => mediaQuery.removeEventListener('change', onSystemThemeChange);\n }\n\n mediaQuery.addListener(onSystemThemeChange);\n return () => mediaQuery.removeListener(onSystemThemeChange);\n }, []);\n\n const resolvedMode = React.useMemo<'light' | 'dark'>(() => {\n const mode = optionsRef.current.theme?.mode || 'light';\n if (mode === 'system') {\n return isSystemDark ? 'dark' : 'light';\n }\n return mode === 'dark' ? 'dark' : 'light';\n }, [isSystemDark]);\n\n const palette = React.useMemo(() => {\n if (resolvedMode === 'dark') {\n return {\n background: '#0b1220',\n text: '#e2e8f0',\n subText: '#94a3b8',\n track: '#1f2937',\n spinnerTrack: '#334155',\n };\n }\n\n return {\n background: '#f5f7fb',\n text: '#51606f',\n subText: '#94a3b8',\n track: '#e9eff5',\n spinnerTrack: '#d9e2ec',\n };\n }, [resolvedMode]);\n\n // 如果提供了自定义启动屏组件,使用自定义组件\n const CustomSplashScreen = optionsRef.current.splashScreen;\n if (CustomSplashScreen) {\n const customProps: SplashScreenCustomProps = {\n progress,\n currentStep,\n isInitializing,\n };\n return <CustomSplashScreen {...customProps} />;\n }\n\n // 默认启动屏 UI\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"应用正在加载\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100vh',\n width: '100%',\n gap: 24,\n background: palette.background,\n color: palette.text,\n }}\n >\n <div\n aria-label=\"加载中\"\n style={{\n width: 42,\n height: 42,\n border: `4px solid ${palette.spinnerTrack}`,\n borderTopColor: 'var(--app-primary-color, #2f80ed)',\n borderRadius: '50%',\n animation: 'secra-spin 1s linear infinite',\n }}\n />\n <div style={{ width: '300px' }}>\n <div\n aria-label={`加载进度 ${progress}%`}\n style={{\n height: 12,\n background: palette.track,\n borderRadius: 999,\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n width: `${Math.max(0, Math.min(100, progress))}%`,\n height: '100%',\n background: 'var(--app-primary-color, #2f80ed)',\n transition: 'width 0.2s ease',\n }}\n />\n </div>\n <div style={{ marginTop: 8, textAlign: 'right', fontSize: 12, color: palette.text }}>\n {progress}%\n </div>\n </div>\n <div\n role=\"status\"\n aria-live=\"polite\"\n style={{\n fontSize: 14,\n color: palette.text,\n textAlign: 'center',\n }}\n >\n {currentStep}\n {estimatedTime !== null && estimatedTime > 0 && (\n <div style={{ fontSize: 12, color: palette.subText, marginTop: 8 }}>\n 预计还需 {Math.ceil(estimatedTime / 1000)} 秒\n </div>\n )}\n </div>\n <style>\n {`@keyframes secra-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}\n </style>\n </div>\n );\n});\n\nSplashScreen.displayName = 'SplashScreen';\n\nexport { SplashScreen };\n"],"names":["React","useEffect","useState","useRef","memo","useCallback","logger","initialization","initializationErrorState","SplashScreen","options","onComplete","progress","setProgress","currentStep","setCurrentStep","isInitializing","setIsInitializing","estimatedTime","setEstimatedTime","isSystemDark","setIsSystemDark","window","matchMedia","matches","hasCompletedRef","onCompleteRef","optionsRef","startTimeRef","Date","now","minDisplayTimeRef","minSplashScreenTime","progressUpdateTimerRef","rafRef","lastProgressRef","progressHistoryRef","current","debouncedProgressUpdate","progressValue","step","cancelAnimationFrame","push","time","length","shift","history","first","last","progressDelta","timeDelta","progressPerMs","remainingProgress","estimatedMs","Math","max","round","requestAnimationFrame","performInitialization","info","context","elapsedTime","dynamicMinTime","min","remainingTime","Promise","resolve","setTimeout","clearTimeout","error","setError","config","isReady","duration","mediaQuery","onSystemThemeChange","event","addEventListener","removeEventListener","addListener","removeListener","resolvedMode","useMemo","mode","theme","palette","background","text","subText","track","spinnerTrack","CustomSplashScreen","splashScreen","customProps","div","role","aria-live","aria-label","style","display","flexDirection","alignItems","justifyContent","height","width","gap","color","border","borderTopColor","borderRadius","animation","overflow","transition","marginTop","textAlign","fontSize","ceil","displayName"],"mappings":"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"}
|
|
@@ -11,9 +11,9 @@ Object.defineProperty(exports, "initializeServices", {
|
|
|
11
11
|
return initializeServices;
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
|
-
const
|
|
14
|
+
const _logger = require("@vlian/logger");
|
|
15
15
|
const _monitoring = require("@vlian/monitoring");
|
|
16
|
-
const
|
|
16
|
+
const _utils = require("@vlian/utils");
|
|
17
17
|
const _library = require("../../library");
|
|
18
18
|
const _state = require("../../state");
|
|
19
19
|
const _AppEventBus = require("../event/AppEventBus");
|
|
@@ -72,12 +72,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
72
72
|
lastError = error;
|
|
73
73
|
if (attempt < maxRetries) {
|
|
74
74
|
const delay = exponentialBackoff ? retryDelay * Math.pow(2, attempt) : retryDelay;
|
|
75
|
-
|
|
75
|
+
_logger.logger.warn(`${serviceName} 初始化失败(尝试 ${attempt + 1}/${maxRetries + 1}),${delay}ms 后重试...`, error);
|
|
76
76
|
await new Promise((resolve)=>setTimeout(resolve, delay));
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
_logger.logger.error(`${serviceName} 初始化失败,已重试 ${maxRetries} 次`);
|
|
81
81
|
throw lastError;
|
|
82
82
|
}
|
|
83
83
|
async function initializeServices(options = {}) {
|
|
@@ -94,7 +94,7 @@ async function initializeServices(options = {}) {
|
|
|
94
94
|
const monitoringPromise = withRetry(()=>Promise.resolve((0, _monitoring.initMonitoring)({
|
|
95
95
|
...options.errorMonitor,
|
|
96
96
|
onError: (error)=>{
|
|
97
|
-
|
|
97
|
+
_logger.logger.error('监控服务捕获到错误:', error);
|
|
98
98
|
options.errorMonitor?.onError?.(error);
|
|
99
99
|
}
|
|
100
100
|
})), retryConfig, '监控服务');
|
|
@@ -136,9 +136,9 @@ async function initializeServices(options = {}) {
|
|
|
136
136
|
stateManagerPromise,
|
|
137
137
|
eventBusPromise
|
|
138
138
|
]);
|
|
139
|
-
|
|
139
|
+
_logger.logger.info('关键服务初始化完成');
|
|
140
140
|
// 初始化性能监控(依赖监控服务,必须在监控服务初始化后)
|
|
141
|
-
const performanceMonitor = new
|
|
141
|
+
const performanceMonitor = new _utils.PerformanceMonitor({
|
|
142
142
|
...options.performanceMonitor,
|
|
143
143
|
onReport: (metrics)=>{
|
|
144
144
|
monitoring.reportPerformance(metrics);
|
|
@@ -154,7 +154,7 @@ async function initializeServices(options = {}) {
|
|
|
154
154
|
window.addEventListener('beforeunload', cleanupHandler);
|
|
155
155
|
}
|
|
156
156
|
const criticalServicesDuration = performance.now() - startTime;
|
|
157
|
-
|
|
157
|
+
_logger.logger.debug(`关键服务初始化完成,耗时: ${criticalServicesDuration.toFixed(2)}ms`);
|
|
158
158
|
// ========== 非关键服务:延迟到应用渲染后初始化 ==========
|
|
159
159
|
// 这些服务不影响首屏渲染,可以在空闲时初始化
|
|
160
160
|
/**
|
|
@@ -183,9 +183,9 @@ async function initializeServices(options = {}) {
|
|
|
183
183
|
initAnalytics(options.analytics);
|
|
184
184
|
return true;
|
|
185
185
|
}), retryConfig, '分析服务');
|
|
186
|
-
|
|
186
|
+
_logger.logger.debug('分析服务初始化完成');
|
|
187
187
|
} catch (error) {
|
|
188
|
-
|
|
188
|
+
_logger.logger.warn('分析服务初始化失败(不影响应用运行):', error);
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
// 2. 运行时安全服务(可选,非关键)
|
|
@@ -195,15 +195,15 @@ async function initializeServices(options = {}) {
|
|
|
195
195
|
RuntimeSecurity.initialize(options.runtimeSecurity);
|
|
196
196
|
return true;
|
|
197
197
|
}), retryConfig, '运行时安全服务');
|
|
198
|
-
|
|
198
|
+
_logger.logger.debug('运行时安全服务初始化完成');
|
|
199
199
|
} catch (error) {
|
|
200
|
-
|
|
200
|
+
_logger.logger.warn('运行时安全服务初始化失败(不影响应用运行):', error);
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
const nonCriticalDuration = performance.now() - nonCriticalStartTime;
|
|
204
|
-
|
|
204
|
+
_logger.logger.debug(`非关键服务初始化完成,耗时: ${nonCriticalDuration.toFixed(2)}ms`);
|
|
205
205
|
} catch (error) {
|
|
206
|
-
|
|
206
|
+
_logger.logger.warn('非关键服务初始化过程中出现错误:', error);
|
|
207
207
|
} finally{
|
|
208
208
|
resolve();
|
|
209
209
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/startup/initializeServices.ts"],"sourcesContent":["/**\n * 服务初始化模块\n * 负责初始化框架所需的各种服务\n */\n\nimport { logger } from '../../utils';\nimport { initMonitoring } from '@vlian/monitoring';\nimport type { MonitoringService } from '@vlian/monitoring';\nimport { PerformanceMonitor } from '../../utils/performance';\nimport { storage } from '../../library';\nimport { StateManager } from '../../state';\nimport type { StartOptions } from '../types';\nimport { AppEventBus } from '../event/AppEventBus';\nimport type { AppEventBusConfig } from '../event/types';\n\n/**\n * 重试配置\n */\nexport interface RetryConfig {\n /**\n * 最大重试次数\n * @default 3\n */\n maxRetries?: number;\n /**\n * 重试延迟(毫秒)\n * @default 1000\n */\n retryDelay?: number;\n /**\n * 是否启用指数退避\n * @default true\n */\n exponentialBackoff?: boolean;\n}\n\n/**\n * 服务初始化结果\n */\nexport interface ServicesInitResult {\n /**\n * 监控服务实例\n */\n monitoring: MonitoringService;\n\n /**\n * 性能监控实例\n */\n performanceMonitor: PerformanceMonitor;\n\n /**\n * 状态管理器实例\n */\n stateManager: StateManager;\n\n /**\n * 事件总线实例\n */\n eventBus: AppEventBus;\n\n /**\n * 延迟初始化非关键服务的函数\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n initializeNonCriticalServices?: () => Promise<void>;\n}\n\n/**\n * 带重试的异步函数执行器\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n config: RetryConfig = {},\n serviceName: string\n): Promise<T> {\n const maxRetries = config.maxRetries ?? 3;\n const retryDelay = config.retryDelay ?? 1000;\n const exponentialBackoff = config.exponentialBackoff ?? true;\n\n let lastError: unknown;\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n \n if (attempt < maxRetries) {\n const delay = exponentialBackoff \n ? retryDelay * Math.pow(2, attempt)\n : retryDelay;\n \n logger.warn(\n `${serviceName} 初始化失败(尝试 ${attempt + 1}/${maxRetries + 1}),${delay}ms 后重试...`,\n error\n );\n \n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n \n logger.error(`${serviceName} 初始化失败,已重试 ${maxRetries} 次`);\n throw lastError;\n}\n\n/**\n * 初始化所有服务\n * \n * 优化:\n * 1. 区分关键服务和非关键服务\n * 2. 关键服务并行初始化,缩短首屏时间\n * 3. 非关键服务延迟到应用渲染后初始化,使用 requestIdleCallback 在空闲时初始化\n * 4. 实现服务初始化失败重试机制,提高启动成功率\n * \n * @param options - 启动配置选项\n * @returns 服务初始化结果\n */\nexport async function initializeServices(\n options: StartOptions = {}\n): Promise<ServicesInitResult> {\n const startTime = performance.now();\n \n // 重试配置\n const retryConfig: RetryConfig = {\n maxRetries: options.serviceRetry?.maxRetries ?? 3,\n retryDelay: options.serviceRetry?.retryDelay ?? 1000,\n exponentialBackoff: options.serviceRetry?.exponentialBackoff ?? true,\n };\n\n // ========== 关键服务:必须在应用渲染前初始化 ==========\n // 这些服务是应用运行的基础,必须并行初始化完成\n\n // 1. 监控服务(必须最先初始化,因为其他服务可能依赖它)\n const monitoringPromise = withRetry(\n () => Promise.resolve(initMonitoring({\n ...options.errorMonitor,\n onError: (error) => {\n logger.error('监控服务捕获到错误:', error);\n options.errorMonitor?.onError?.(error);\n },\n })),\n retryConfig,\n '监控服务'\n );\n\n // 2. 存储服务(关键服务,应用可能需要立即使用存储)\n const storagePromise = withRetry(\n () => Promise.resolve().then(() => {\n storage.initialize(options.storageOptions);\n return storage;\n }),\n retryConfig,\n '存储服务'\n );\n\n // 3. 状态管理器(关键服务,应用状态管理的基础)\n const stateManagerPromise = withRetry(\n () => Promise.resolve().then(() => {\n if (options.stateManager !== undefined) {\n return new StateManager(options.stateManager);\n } else {\n // 默认初始化状态管理器\n return new StateManager({\n enableRegistry: true,\n defaultScope: 'app',\n });\n }\n }),\n retryConfig,\n '状态管理器'\n );\n\n // 4. 事件总线(关键服务,用于应用内部通信)\n const eventBusPromise = withRetry(\n () => Promise.resolve().then(() => {\n const eventBusConfig: AppEventBusConfig = {\n enableTracking: options.eventBus?.enableTracking ?? (process.env.NODE_ENV === 'development'),\n maxHistorySize: options.eventBus?.maxHistorySize ?? 100,\n enableValidation: options.eventBus?.enableValidation ?? false,\n enablePerformanceMonitoring: options.eventBus?.enablePerformanceMonitoring ?? (process.env.NODE_ENV === 'development'),\n namespacePrefix: options.eventBus?.namespacePrefix,\n instanceId: options.eventBus?.instanceId,\n enableSecurityMode: options.eventBus?.enableSecurityMode ?? false,\n allowedSources: options.eventBus?.allowedSources,\n };\n return new AppEventBus(eventBusConfig);\n }),\n retryConfig,\n '事件总线'\n );\n\n // 并行执行关键服务初始化\n const [monitoring, , stateManager, eventBus] = await Promise.all([\n monitoringPromise,\n storagePromise,\n stateManagerPromise,\n eventBusPromise,\n ]);\n\n logger.info('关键服务初始化完成');\n\n // 初始化性能监控(依赖监控服务,必须在监控服务初始化后)\n const performanceMonitor = new PerformanceMonitor({\n ...options.performanceMonitor,\n onReport: (metrics) => {\n monitoring.reportPerformance(metrics);\n options.performanceMonitor?.onReport?.(metrics);\n },\n });\n\n // 在页面卸载时清理性能监控\n if (typeof window !== 'undefined') {\n const cleanupHandler = () => {\n performanceMonitor.disconnect();\n window.removeEventListener('beforeunload', cleanupHandler);\n };\n window.addEventListener('beforeunload', cleanupHandler);\n }\n\n const criticalServicesDuration = performance.now() - startTime;\n logger.debug(`关键服务初始化完成,耗时: ${criticalServicesDuration.toFixed(2)}ms`);\n\n // ========== 非关键服务:延迟到应用渲染后初始化 ==========\n // 这些服务不影响首屏渲染,可以在空闲时初始化\n\n /**\n * 延迟初始化非关键服务\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n const initializeNonCriticalServices = async (): Promise<void> => {\n const nonCriticalStartTime = performance.now();\n \n // 使用 requestIdleCallback 在浏览器空闲时初始化非关键服务\n // 如果不支持 requestIdleCallback,则使用 setTimeout 延迟执行\n const scheduleInit = (callback: () => void) => {\n if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {\n window.requestIdleCallback(callback, { timeout: 5000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n return new Promise<void>((resolve) => {\n scheduleInit(async () => {\n try {\n // 1. 分析服务(可选,非关键)\n if (options.analytics) {\n try {\n await withRetry(\n () => import('../../utils/analytics').then(({ initAnalytics }) => {\n initAnalytics(options.analytics!);\n return true;\n }),\n retryConfig,\n '分析服务'\n );\n logger.debug('分析服务初始化完成');\n } catch (error) {\n logger.warn('分析服务初始化失败(不影响应用运行):', error);\n }\n }\n\n // 2. 运行时安全服务(可选,非关键)\n if (options.runtimeSecurity) {\n try {\n await withRetry(\n () => import('../../utils/runtimeSecurity').then(({ RuntimeSecurity }) => {\n RuntimeSecurity.initialize(options.runtimeSecurity!);\n return true;\n }),\n retryConfig,\n '运行时安全服务'\n );\n logger.debug('运行时安全服务初始化完成');\n } catch (error) {\n logger.warn('运行时安全服务初始化失败(不影响应用运行):', error);\n }\n }\n\n const nonCriticalDuration = performance.now() - nonCriticalStartTime;\n logger.debug(`非关键服务初始化完成,耗时: ${nonCriticalDuration.toFixed(2)}ms`);\n } catch (error) {\n logger.warn('非关键服务初始化过程中出现错误:', error);\n } finally {\n resolve();\n }\n });\n });\n };\n\n // 记录关键服务初始化性能指标\n if (monitoring.reportPerformance) {\n monitoring.reportPerformance({\n serviceInitDuration: criticalServicesDuration,\n } as any);\n }\n\n return {\n monitoring,\n performanceMonitor,\n stateManager,\n eventBus,\n initializeNonCriticalServices,\n };\n}\n"],"names":["initializeServices","withRetry","fn","config","serviceName","maxRetries","retryDelay","exponentialBackoff","lastError","attempt","error","delay","Math","pow","logger","warn","Promise","resolve","setTimeout","options","startTime","performance","now","retryConfig","serviceRetry","monitoringPromise","initMonitoring","errorMonitor","onError","storagePromise","then","storage","initialize","storageOptions","stateManagerPromise","stateManager","undefined","StateManager","enableRegistry","defaultScope","eventBusPromise","eventBusConfig","enableTracking","eventBus","process","env","NODE_ENV","maxHistorySize","enableValidation","enablePerformanceMonitoring","namespacePrefix","instanceId","enableSecurityMode","allowedSources","AppEventBus","monitoring","all","info","performanceMonitor","PerformanceMonitor","onReport","metrics","reportPerformance","window","cleanupHandler","disconnect","removeEventListener","addEventListener","criticalServicesDuration","debug","toFixed","initializeNonCriticalServices","nonCriticalStartTime","scheduleInit","callback","requestIdleCallback","timeout","analytics","initAnalytics","runtimeSecurity","RuntimeSecurity","nonCriticalDuration","serviceInitDuration"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/startup/initializeServices.ts"],"sourcesContent":["/**\n * 服务初始化模块\n * 负责初始化框架所需的各种服务\n */\n\nimport { logger } from '@vlian/logger';\nimport { initMonitoring } from '@vlian/monitoring';\nimport type { MonitoringService } from '@vlian/monitoring';\nimport { PerformanceMonitor } from '@vlian/utils';\nimport { storage } from '../../library';\nimport { StateManager } from '../../state';\nimport type { StartOptions } from '../types';\nimport { AppEventBus } from '../event/AppEventBus';\nimport type { AppEventBusConfig } from '../event/types';\n\n/**\n * 重试配置\n */\nexport interface RetryConfig {\n /**\n * 最大重试次数\n * @default 3\n */\n maxRetries?: number;\n /**\n * 重试延迟(毫秒)\n * @default 1000\n */\n retryDelay?: number;\n /**\n * 是否启用指数退避\n * @default true\n */\n exponentialBackoff?: boolean;\n}\n\n/**\n * 服务初始化结果\n */\nexport interface ServicesInitResult {\n /**\n * 监控服务实例\n */\n monitoring: MonitoringService;\n\n /**\n * 性能监控实例\n */\n performanceMonitor: PerformanceMonitor;\n\n /**\n * 状态管理器实例\n */\n stateManager: StateManager;\n\n /**\n * 事件总线实例\n */\n eventBus: AppEventBus;\n\n /**\n * 延迟初始化非关键服务的函数\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n initializeNonCriticalServices?: () => Promise<void>;\n}\n\n/**\n * 带重试的异步函数执行器\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n config: RetryConfig = {},\n serviceName: string\n): Promise<T> {\n const maxRetries = config.maxRetries ?? 3;\n const retryDelay = config.retryDelay ?? 1000;\n const exponentialBackoff = config.exponentialBackoff ?? true;\n\n let lastError: unknown;\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n \n if (attempt < maxRetries) {\n const delay = exponentialBackoff \n ? retryDelay * Math.pow(2, attempt)\n : retryDelay;\n \n logger.warn(\n `${serviceName} 初始化失败(尝试 ${attempt + 1}/${maxRetries + 1}),${delay}ms 后重试...`,\n error\n );\n \n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n \n logger.error(`${serviceName} 初始化失败,已重试 ${maxRetries} 次`);\n throw lastError;\n}\n\n/**\n * 初始化所有服务\n * \n * 优化:\n * 1. 区分关键服务和非关键服务\n * 2. 关键服务并行初始化,缩短首屏时间\n * 3. 非关键服务延迟到应用渲染后初始化,使用 requestIdleCallback 在空闲时初始化\n * 4. 实现服务初始化失败重试机制,提高启动成功率\n * \n * @param options - 启动配置选项\n * @returns 服务初始化结果\n */\nexport async function initializeServices(\n options: StartOptions = {}\n): Promise<ServicesInitResult> {\n const startTime = performance.now();\n \n // 重试配置\n const retryConfig: RetryConfig = {\n maxRetries: options.serviceRetry?.maxRetries ?? 3,\n retryDelay: options.serviceRetry?.retryDelay ?? 1000,\n exponentialBackoff: options.serviceRetry?.exponentialBackoff ?? true,\n };\n\n // ========== 关键服务:必须在应用渲染前初始化 ==========\n // 这些服务是应用运行的基础,必须并行初始化完成\n\n // 1. 监控服务(必须最先初始化,因为其他服务可能依赖它)\n const monitoringPromise = withRetry(\n () => Promise.resolve(initMonitoring({\n ...options.errorMonitor,\n onError: (error) => {\n logger.error('监控服务捕获到错误:', error);\n options.errorMonitor?.onError?.(error);\n },\n })),\n retryConfig,\n '监控服务'\n );\n\n // 2. 存储服务(关键服务,应用可能需要立即使用存储)\n const storagePromise = withRetry(\n () => Promise.resolve().then(() => {\n storage.initialize(options.storageOptions);\n return storage;\n }),\n retryConfig,\n '存储服务'\n );\n\n // 3. 状态管理器(关键服务,应用状态管理的基础)\n const stateManagerPromise = withRetry(\n () => Promise.resolve().then(() => {\n if (options.stateManager !== undefined) {\n return new StateManager(options.stateManager);\n } else {\n // 默认初始化状态管理器\n return new StateManager({\n enableRegistry: true,\n defaultScope: 'app',\n });\n }\n }),\n retryConfig,\n '状态管理器'\n );\n\n // 4. 事件总线(关键服务,用于应用内部通信)\n const eventBusPromise = withRetry(\n () => Promise.resolve().then(() => {\n const eventBusConfig: AppEventBusConfig = {\n enableTracking: options.eventBus?.enableTracking ?? (process.env.NODE_ENV === 'development'),\n maxHistorySize: options.eventBus?.maxHistorySize ?? 100,\n enableValidation: options.eventBus?.enableValidation ?? false,\n enablePerformanceMonitoring: options.eventBus?.enablePerformanceMonitoring ?? (process.env.NODE_ENV === 'development'),\n namespacePrefix: options.eventBus?.namespacePrefix,\n instanceId: options.eventBus?.instanceId,\n enableSecurityMode: options.eventBus?.enableSecurityMode ?? false,\n allowedSources: options.eventBus?.allowedSources,\n };\n return new AppEventBus(eventBusConfig);\n }),\n retryConfig,\n '事件总线'\n );\n\n // 并行执行关键服务初始化\n const [monitoring, , stateManager, eventBus] = await Promise.all([\n monitoringPromise,\n storagePromise,\n stateManagerPromise,\n eventBusPromise,\n ]);\n\n logger.info('关键服务初始化完成');\n\n // 初始化性能监控(依赖监控服务,必须在监控服务初始化后)\n const performanceMonitor = new PerformanceMonitor({\n ...options.performanceMonitor,\n onReport: (metrics) => {\n monitoring.reportPerformance(metrics);\n options.performanceMonitor?.onReport?.(metrics);\n },\n });\n\n // 在页面卸载时清理性能监控\n if (typeof window !== 'undefined') {\n const cleanupHandler = () => {\n performanceMonitor.disconnect();\n window.removeEventListener('beforeunload', cleanupHandler);\n };\n window.addEventListener('beforeunload', cleanupHandler);\n }\n\n const criticalServicesDuration = performance.now() - startTime;\n logger.debug(`关键服务初始化完成,耗时: ${criticalServicesDuration.toFixed(2)}ms`);\n\n // ========== 非关键服务:延迟到应用渲染后初始化 ==========\n // 这些服务不影响首屏渲染,可以在空闲时初始化\n\n /**\n * 延迟初始化非关键服务\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n const initializeNonCriticalServices = async (): Promise<void> => {\n const nonCriticalStartTime = performance.now();\n \n // 使用 requestIdleCallback 在浏览器空闲时初始化非关键服务\n // 如果不支持 requestIdleCallback,则使用 setTimeout 延迟执行\n const scheduleInit = (callback: () => void) => {\n if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {\n window.requestIdleCallback(callback, { timeout: 5000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n return new Promise<void>((resolve) => {\n scheduleInit(async () => {\n try {\n // 1. 分析服务(可选,非关键)\n if (options.analytics) {\n try {\n await withRetry(\n () => import('../../utils/analytics').then(({ initAnalytics }) => {\n initAnalytics(options.analytics!);\n return true;\n }),\n retryConfig,\n '分析服务'\n );\n logger.debug('分析服务初始化完成');\n } catch (error) {\n logger.warn('分析服务初始化失败(不影响应用运行):', error);\n }\n }\n\n // 2. 运行时安全服务(可选,非关键)\n if (options.runtimeSecurity) {\n try {\n await withRetry(\n () => import('../../utils/runtimeSecurity').then(({ RuntimeSecurity }) => {\n RuntimeSecurity.initialize(options.runtimeSecurity!);\n return true;\n }),\n retryConfig,\n '运行时安全服务'\n );\n logger.debug('运行时安全服务初始化完成');\n } catch (error) {\n logger.warn('运行时安全服务初始化失败(不影响应用运行):', error);\n }\n }\n\n const nonCriticalDuration = performance.now() - nonCriticalStartTime;\n logger.debug(`非关键服务初始化完成,耗时: ${nonCriticalDuration.toFixed(2)}ms`);\n } catch (error) {\n logger.warn('非关键服务初始化过程中出现错误:', error);\n } finally {\n resolve();\n }\n });\n });\n };\n\n // 记录关键服务初始化性能指标\n if (monitoring.reportPerformance) {\n monitoring.reportPerformance({\n serviceInitDuration: criticalServicesDuration,\n } as any);\n }\n\n return {\n monitoring,\n performanceMonitor,\n stateManager,\n eventBus,\n initializeNonCriticalServices,\n };\n}\n"],"names":["initializeServices","withRetry","fn","config","serviceName","maxRetries","retryDelay","exponentialBackoff","lastError","attempt","error","delay","Math","pow","logger","warn","Promise","resolve","setTimeout","options","startTime","performance","now","retryConfig","serviceRetry","monitoringPromise","initMonitoring","errorMonitor","onError","storagePromise","then","storage","initialize","storageOptions","stateManagerPromise","stateManager","undefined","StateManager","enableRegistry","defaultScope","eventBusPromise","eventBusConfig","enableTracking","eventBus","process","env","NODE_ENV","maxHistorySize","enableValidation","enablePerformanceMonitoring","namespacePrefix","instanceId","enableSecurityMode","allowedSources","AppEventBus","monitoring","all","info","performanceMonitor","PerformanceMonitor","onReport","metrics","reportPerformance","window","cleanupHandler","disconnect","removeEventListener","addEventListener","criticalServicesDuration","debug","toFixed","initializeNonCriticalServices","nonCriticalStartTime","scheduleInit","callback","requestIdleCallback","timeout","analytics","initAnalytics","runtimeSecurity","RuntimeSecurity","nonCriticalDuration","serviceInitDuration"],"mappings":"AAAA;;;CAGC;;;;+BAmHqBA;;;eAAAA;;;wBAjHC;4BACQ;uBAEI;yBACX;uBACK;6BAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuD5B;;CAEC,GACD,eAAeC,UACbC,EAAoB,EACpBC,SAAsB,CAAC,CAAC,EACxBC,WAAmB;IAEnB,MAAMC,aAAaF,OAAOE,UAAU,IAAI;IACxC,MAAMC,aAAaH,OAAOG,UAAU,IAAI;IACxC,MAAMC,qBAAqBJ,OAAOI,kBAAkB,IAAI;IAExD,IAAIC;IAEJ,IAAK,IAAIC,UAAU,GAAGA,WAAWJ,YAAYI,UAAW;QACtD,IAAI;YACF,OAAO,MAAMP;QACf,EAAE,OAAOQ,OAAO;YACdF,YAAYE;YAEZ,IAAID,UAAUJ,YAAY;gBACxB,MAAMM,QAAQJ,qBACVD,aAAaM,KAAKC,GAAG,CAAC,GAAGJ,WACzBH;gBAEJQ,cAAM,CAACC,IAAI,CACT,GAAGX,YAAY,UAAU,EAAEK,UAAU,EAAE,CAAC,EAAEJ,aAAa,EAAE,EAAE,EAAEM,MAAM,SAAS,CAAC,EAC7ED;gBAGF,MAAM,IAAIM,QAAQC,CAAAA,UAAWC,WAAWD,SAASN;YACnD;QACF;IACF;IAEAG,cAAM,CAACJ,KAAK,CAAC,GAAGN,YAAY,WAAW,EAAEC,WAAW,EAAE,CAAC;IACvD,MAAMG;AACR;AAcO,eAAeR,mBACpBmB,UAAwB,CAAC,CAAC;IAE1B,MAAMC,YAAYC,YAAYC,GAAG;IAEjC,OAAO;IACP,MAAMC,cAA2B;QAC/BlB,YAAYc,QAAQK,YAAY,EAAEnB,cAAc;QAChDC,YAAYa,QAAQK,YAAY,EAAElB,cAAc;QAChDC,oBAAoBY,QAAQK,YAAY,EAAEjB,sBAAsB;IAClE;IAEA,yCAAyC;IACzC,yBAAyB;IAEzB,+BAA+B;IAC/B,MAAMkB,oBAAoBxB,UACxB,IAAMe,QAAQC,OAAO,CAACS,IAAAA,0BAAc,EAAC;YACnC,GAAGP,QAAQQ,YAAY;YACvBC,SAAS,CAAClB;gBACRI,cAAM,CAACJ,KAAK,CAAC,cAAcA;gBAC3BS,QAAQQ,YAAY,EAAEC,UAAUlB;YAClC;QACF,KACAa,aACA;IAGF,6BAA6B;IAC7B,MAAMM,iBAAiB5B,UACrB,IAAMe,QAAQC,OAAO,GAAGa,IAAI,CAAC;YAC3BC,gBAAO,CAACC,UAAU,CAACb,QAAQc,cAAc;YACzC,OAAOF,gBAAO;QAChB,IACAR,aACA;IAGF,2BAA2B;IAC3B,MAAMW,sBAAsBjC,UAC1B,IAAMe,QAAQC,OAAO,GAAGa,IAAI,CAAC;YAC3B,IAAIX,QAAQgB,YAAY,KAAKC,WAAW;gBACtC,OAAO,IAAIC,mBAAY,CAAClB,QAAQgB,YAAY;YAC9C,OAAO;gBACL,aAAa;gBACb,OAAO,IAAIE,mBAAY,CAAC;oBACtBC,gBAAgB;oBAChBC,cAAc;gBAChB;YACF;QACF,IACAhB,aACA;IAGF,yBAAyB;IACzB,MAAMiB,kBAAkBvC,UACtB,IAAMe,QAAQC,OAAO,GAAGa,IAAI,CAAC;YAC3B,MAAMW,iBAAoC;gBACxCC,gBAAgBvB,QAAQwB,QAAQ,EAAED,kBAAmBE,QAAQC,GAAG,CAACC,QAAQ,KAAK;gBAC9EC,gBAAgB5B,QAAQwB,QAAQ,EAAEI,kBAAkB;gBACpDC,kBAAkB7B,QAAQwB,QAAQ,EAAEK,oBAAoB;gBACxDC,6BAA6B9B,QAAQwB,QAAQ,EAAEM,+BAAgCL,QAAQC,GAAG,CAACC,QAAQ,KAAK;gBACxGI,iBAAiB/B,QAAQwB,QAAQ,EAAEO;gBACnCC,YAAYhC,QAAQwB,QAAQ,EAAEQ;gBAC9BC,oBAAoBjC,QAAQwB,QAAQ,EAAES,sBAAsB;gBAC5DC,gBAAgBlC,QAAQwB,QAAQ,EAAEU;YACpC;YACA,OAAO,IAAIC,wBAAW,CAACb;QACzB,IACAlB,aACA;IAGF,cAAc;IACd,MAAM,CAACgC,cAAcpB,cAAcQ,SAAS,GAAG,MAAM3B,QAAQwC,GAAG,CAAC;QAC/D/B;QACAI;QACAK;QACAM;KACD;IAED1B,cAAM,CAAC2C,IAAI,CAAC;IAEZ,8BAA8B;IAC9B,MAAMC,qBAAqB,IAAIC,yBAAkB,CAAC;QAChD,GAAGxC,QAAQuC,kBAAkB;QAC7BE,UAAU,CAACC;YACTN,WAAWO,iBAAiB,CAACD;YAC7B1C,QAAQuC,kBAAkB,EAAEE,WAAWC;QACzC;IACF;IAEA,eAAe;IACf,IAAI,OAAOE,WAAW,aAAa;QACjC,MAAMC,iBAAiB;YACrBN,mBAAmBO,UAAU;YAC7BF,OAAOG,mBAAmB,CAAC,gBAAgBF;QAC7C;QACAD,OAAOI,gBAAgB,CAAC,gBAAgBH;IAC1C;IAEA,MAAMI,2BAA2B/C,YAAYC,GAAG,KAAKF;IACrDN,cAAM,CAACuD,KAAK,CAAC,CAAC,cAAc,EAAED,yBAAyBE,OAAO,CAAC,GAAG,EAAE,CAAC;IAErE,0CAA0C;IAC1C,wBAAwB;IAExB;;;GAGC,GACD,MAAMC,gCAAgC;QACpC,MAAMC,uBAAuBnD,YAAYC,GAAG;QAE5C,yCAAyC;QACzC,gDAAgD;QAChD,MAAMmD,eAAe,CAACC;YACpB,IAAI,OAAOX,WAAW,eAAe,yBAAyBA,QAAQ;gBACpEA,OAAOY,mBAAmB,CAACD,UAAU;oBAAEE,SAAS;gBAAK;YACvD,OAAO;gBACL1D,WAAWwD,UAAU;YACvB;QACF;QAEA,OAAO,IAAI1D,QAAc,CAACC;YACxBwD,aAAa;gBACX,IAAI;oBACF,kBAAkB;oBAClB,IAAItD,QAAQ0D,SAAS,EAAE;wBACrB,IAAI;4BACF,MAAM5E,UACJ,IAAM,mEAAA,QAAO,2BAAyB6B,IAAI,CAAC,CAAC,EAAEgD,aAAa,EAAE;oCAC3DA,cAAc3D,QAAQ0D,SAAS;oCAC/B,OAAO;gCACT,IACAtD,aACA;4BAEFT,cAAM,CAACuD,KAAK,CAAC;wBACf,EAAE,OAAO3D,OAAO;4BACdI,cAAM,CAACC,IAAI,CAAC,uBAAuBL;wBACrC;oBACF;oBAEA,qBAAqB;oBACrB,IAAIS,QAAQ4D,eAAe,EAAE;wBAC3B,IAAI;4BACF,MAAM9E,UACJ,IAAM,mEAAA,QAAO,iCAA+B6B,IAAI,CAAC,CAAC,EAAEkD,eAAe,EAAE;oCACnEA,gBAAgBhD,UAAU,CAACb,QAAQ4D,eAAe;oCAClD,OAAO;gCACT,IACAxD,aACA;4BAEFT,cAAM,CAACuD,KAAK,CAAC;wBACf,EAAE,OAAO3D,OAAO;4BACdI,cAAM,CAACC,IAAI,CAAC,0BAA0BL;wBACxC;oBACF;oBAEA,MAAMuE,sBAAsB5D,YAAYC,GAAG,KAAKkD;oBAChD1D,cAAM,CAACuD,KAAK,CAAC,CAAC,eAAe,EAAEY,oBAAoBX,OAAO,CAAC,GAAG,EAAE,CAAC;gBACnE,EAAE,OAAO5D,OAAO;oBACdI,cAAM,CAACC,IAAI,CAAC,oBAAoBL;gBAClC,SAAU;oBACRO;gBACF;YACF;QACF;IACF;IAEA,gBAAgB;IAChB,IAAIsC,WAAWO,iBAAiB,EAAE;QAChCP,WAAWO,iBAAiB,CAAC;YAC3BoB,qBAAqBd;QACvB;IACF;IAEA,OAAO;QACLb;QACAG;QACAvB;QACAQ;QACA4B;IACF;AACF"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* 负责初始化框架所需的各种服务
|
|
4
4
|
*/
|
|
5
5
|
import type { MonitoringService } from '@vlian/monitoring';
|
|
6
|
-
import { PerformanceMonitor } from '
|
|
6
|
+
import { PerformanceMonitor } from '@vlian/utils';
|
|
7
7
|
import { StateManager } from '../../state';
|
|
8
8
|
import type { StartOptions } from '../types';
|
|
9
9
|
import { AppEventBus } from '../event/AppEventBus';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 服务初始化模块
|
|
3
3
|
* 负责初始化框架所需的各种服务
|
|
4
|
-
*/ import { logger } from "
|
|
4
|
+
*/ import { logger } from "@vlian/logger";
|
|
5
5
|
import { initMonitoring } from "@vlian/monitoring";
|
|
6
|
-
import { PerformanceMonitor } from "
|
|
6
|
+
import { PerformanceMonitor } from "@vlian/utils";
|
|
7
7
|
import { storage } from "../../library";
|
|
8
8
|
import { StateManager } from "../../state";
|
|
9
9
|
import { AppEventBus } from "../event/AppEventBus";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/startup/initializeServices.ts"],"sourcesContent":["/**\n * 服务初始化模块\n * 负责初始化框架所需的各种服务\n */\n\nimport { logger } from '../../utils';\nimport { initMonitoring } from '@vlian/monitoring';\nimport type { MonitoringService } from '@vlian/monitoring';\nimport { PerformanceMonitor } from '../../utils/performance';\nimport { storage } from '../../library';\nimport { StateManager } from '../../state';\nimport type { StartOptions } from '../types';\nimport { AppEventBus } from '../event/AppEventBus';\nimport type { AppEventBusConfig } from '../event/types';\n\n/**\n * 重试配置\n */\nexport interface RetryConfig {\n /**\n * 最大重试次数\n * @default 3\n */\n maxRetries?: number;\n /**\n * 重试延迟(毫秒)\n * @default 1000\n */\n retryDelay?: number;\n /**\n * 是否启用指数退避\n * @default true\n */\n exponentialBackoff?: boolean;\n}\n\n/**\n * 服务初始化结果\n */\nexport interface ServicesInitResult {\n /**\n * 监控服务实例\n */\n monitoring: MonitoringService;\n\n /**\n * 性能监控实例\n */\n performanceMonitor: PerformanceMonitor;\n\n /**\n * 状态管理器实例\n */\n stateManager: StateManager;\n\n /**\n * 事件总线实例\n */\n eventBus: AppEventBus;\n\n /**\n * 延迟初始化非关键服务的函数\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n initializeNonCriticalServices?: () => Promise<void>;\n}\n\n/**\n * 带重试的异步函数执行器\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n config: RetryConfig = {},\n serviceName: string\n): Promise<T> {\n const maxRetries = config.maxRetries ?? 3;\n const retryDelay = config.retryDelay ?? 1000;\n const exponentialBackoff = config.exponentialBackoff ?? true;\n\n let lastError: unknown;\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n \n if (attempt < maxRetries) {\n const delay = exponentialBackoff \n ? retryDelay * Math.pow(2, attempt)\n : retryDelay;\n \n logger.warn(\n `${serviceName} 初始化失败(尝试 ${attempt + 1}/${maxRetries + 1}),${delay}ms 后重试...`,\n error\n );\n \n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n \n logger.error(`${serviceName} 初始化失败,已重试 ${maxRetries} 次`);\n throw lastError;\n}\n\n/**\n * 初始化所有服务\n * \n * 优化:\n * 1. 区分关键服务和非关键服务\n * 2. 关键服务并行初始化,缩短首屏时间\n * 3. 非关键服务延迟到应用渲染后初始化,使用 requestIdleCallback 在空闲时初始化\n * 4. 实现服务初始化失败重试机制,提高启动成功率\n * \n * @param options - 启动配置选项\n * @returns 服务初始化结果\n */\nexport async function initializeServices(\n options: StartOptions = {}\n): Promise<ServicesInitResult> {\n const startTime = performance.now();\n \n // 重试配置\n const retryConfig: RetryConfig = {\n maxRetries: options.serviceRetry?.maxRetries ?? 3,\n retryDelay: options.serviceRetry?.retryDelay ?? 1000,\n exponentialBackoff: options.serviceRetry?.exponentialBackoff ?? true,\n };\n\n // ========== 关键服务:必须在应用渲染前初始化 ==========\n // 这些服务是应用运行的基础,必须并行初始化完成\n\n // 1. 监控服务(必须最先初始化,因为其他服务可能依赖它)\n const monitoringPromise = withRetry(\n () => Promise.resolve(initMonitoring({\n ...options.errorMonitor,\n onError: (error) => {\n logger.error('监控服务捕获到错误:', error);\n options.errorMonitor?.onError?.(error);\n },\n })),\n retryConfig,\n '监控服务'\n );\n\n // 2. 存储服务(关键服务,应用可能需要立即使用存储)\n const storagePromise = withRetry(\n () => Promise.resolve().then(() => {\n storage.initialize(options.storageOptions);\n return storage;\n }),\n retryConfig,\n '存储服务'\n );\n\n // 3. 状态管理器(关键服务,应用状态管理的基础)\n const stateManagerPromise = withRetry(\n () => Promise.resolve().then(() => {\n if (options.stateManager !== undefined) {\n return new StateManager(options.stateManager);\n } else {\n // 默认初始化状态管理器\n return new StateManager({\n enableRegistry: true,\n defaultScope: 'app',\n });\n }\n }),\n retryConfig,\n '状态管理器'\n );\n\n // 4. 事件总线(关键服务,用于应用内部通信)\n const eventBusPromise = withRetry(\n () => Promise.resolve().then(() => {\n const eventBusConfig: AppEventBusConfig = {\n enableTracking: options.eventBus?.enableTracking ?? (process.env.NODE_ENV === 'development'),\n maxHistorySize: options.eventBus?.maxHistorySize ?? 100,\n enableValidation: options.eventBus?.enableValidation ?? false,\n enablePerformanceMonitoring: options.eventBus?.enablePerformanceMonitoring ?? (process.env.NODE_ENV === 'development'),\n namespacePrefix: options.eventBus?.namespacePrefix,\n instanceId: options.eventBus?.instanceId,\n enableSecurityMode: options.eventBus?.enableSecurityMode ?? false,\n allowedSources: options.eventBus?.allowedSources,\n };\n return new AppEventBus(eventBusConfig);\n }),\n retryConfig,\n '事件总线'\n );\n\n // 并行执行关键服务初始化\n const [monitoring, , stateManager, eventBus] = await Promise.all([\n monitoringPromise,\n storagePromise,\n stateManagerPromise,\n eventBusPromise,\n ]);\n\n logger.info('关键服务初始化完成');\n\n // 初始化性能监控(依赖监控服务,必须在监控服务初始化后)\n const performanceMonitor = new PerformanceMonitor({\n ...options.performanceMonitor,\n onReport: (metrics) => {\n monitoring.reportPerformance(metrics);\n options.performanceMonitor?.onReport?.(metrics);\n },\n });\n\n // 在页面卸载时清理性能监控\n if (typeof window !== 'undefined') {\n const cleanupHandler = () => {\n performanceMonitor.disconnect();\n window.removeEventListener('beforeunload', cleanupHandler);\n };\n window.addEventListener('beforeunload', cleanupHandler);\n }\n\n const criticalServicesDuration = performance.now() - startTime;\n logger.debug(`关键服务初始化完成,耗时: ${criticalServicesDuration.toFixed(2)}ms`);\n\n // ========== 非关键服务:延迟到应用渲染后初始化 ==========\n // 这些服务不影响首屏渲染,可以在空闲时初始化\n\n /**\n * 延迟初始化非关键服务\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n const initializeNonCriticalServices = async (): Promise<void> => {\n const nonCriticalStartTime = performance.now();\n \n // 使用 requestIdleCallback 在浏览器空闲时初始化非关键服务\n // 如果不支持 requestIdleCallback,则使用 setTimeout 延迟执行\n const scheduleInit = (callback: () => void) => {\n if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {\n window.requestIdleCallback(callback, { timeout: 5000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n return new Promise<void>((resolve) => {\n scheduleInit(async () => {\n try {\n // 1. 分析服务(可选,非关键)\n if (options.analytics) {\n try {\n await withRetry(\n () => import('../../utils/analytics').then(({ initAnalytics }) => {\n initAnalytics(options.analytics!);\n return true;\n }),\n retryConfig,\n '分析服务'\n );\n logger.debug('分析服务初始化完成');\n } catch (error) {\n logger.warn('分析服务初始化失败(不影响应用运行):', error);\n }\n }\n\n // 2. 运行时安全服务(可选,非关键)\n if (options.runtimeSecurity) {\n try {\n await withRetry(\n () => import('../../utils/runtimeSecurity').then(({ RuntimeSecurity }) => {\n RuntimeSecurity.initialize(options.runtimeSecurity!);\n return true;\n }),\n retryConfig,\n '运行时安全服务'\n );\n logger.debug('运行时安全服务初始化完成');\n } catch (error) {\n logger.warn('运行时安全服务初始化失败(不影响应用运行):', error);\n }\n }\n\n const nonCriticalDuration = performance.now() - nonCriticalStartTime;\n logger.debug(`非关键服务初始化完成,耗时: ${nonCriticalDuration.toFixed(2)}ms`);\n } catch (error) {\n logger.warn('非关键服务初始化过程中出现错误:', error);\n } finally {\n resolve();\n }\n });\n });\n };\n\n // 记录关键服务初始化性能指标\n if (monitoring.reportPerformance) {\n monitoring.reportPerformance({\n serviceInitDuration: criticalServicesDuration,\n } as any);\n }\n\n return {\n monitoring,\n performanceMonitor,\n stateManager,\n eventBus,\n initializeNonCriticalServices,\n };\n}\n"],"names":["logger","initMonitoring","PerformanceMonitor","storage","StateManager","AppEventBus","withRetry","fn","config","serviceName","maxRetries","retryDelay","exponentialBackoff","lastError","attempt","error","delay","Math","pow","warn","Promise","resolve","setTimeout","initializeServices","options","startTime","performance","now","retryConfig","serviceRetry","monitoringPromise","errorMonitor","onError","storagePromise","then","initialize","storageOptions","stateManagerPromise","stateManager","undefined","enableRegistry","defaultScope","eventBusPromise","eventBusConfig","enableTracking","eventBus","process","env","NODE_ENV","maxHistorySize","enableValidation","enablePerformanceMonitoring","namespacePrefix","instanceId","enableSecurityMode","allowedSources","monitoring","all","info","performanceMonitor","onReport","metrics","reportPerformance","window","cleanupHandler","disconnect","removeEventListener","addEventListener","criticalServicesDuration","debug","toFixed","initializeNonCriticalServices","nonCriticalStartTime","scheduleInit","callback","requestIdleCallback","timeout","analytics","initAnalytics","runtimeSecurity","RuntimeSecurity","nonCriticalDuration","serviceInitDuration"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/startup/initializeServices.ts"],"sourcesContent":["/**\n * 服务初始化模块\n * 负责初始化框架所需的各种服务\n */\n\nimport { logger } from '@vlian/logger';\nimport { initMonitoring } from '@vlian/monitoring';\nimport type { MonitoringService } from '@vlian/monitoring';\nimport { PerformanceMonitor } from '@vlian/utils';\nimport { storage } from '../../library';\nimport { StateManager } from '../../state';\nimport type { StartOptions } from '../types';\nimport { AppEventBus } from '../event/AppEventBus';\nimport type { AppEventBusConfig } from '../event/types';\n\n/**\n * 重试配置\n */\nexport interface RetryConfig {\n /**\n * 最大重试次数\n * @default 3\n */\n maxRetries?: number;\n /**\n * 重试延迟(毫秒)\n * @default 1000\n */\n retryDelay?: number;\n /**\n * 是否启用指数退避\n * @default true\n */\n exponentialBackoff?: boolean;\n}\n\n/**\n * 服务初始化结果\n */\nexport interface ServicesInitResult {\n /**\n * 监控服务实例\n */\n monitoring: MonitoringService;\n\n /**\n * 性能监控实例\n */\n performanceMonitor: PerformanceMonitor;\n\n /**\n * 状态管理器实例\n */\n stateManager: StateManager;\n\n /**\n * 事件总线实例\n */\n eventBus: AppEventBus;\n\n /**\n * 延迟初始化非关键服务的函数\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n initializeNonCriticalServices?: () => Promise<void>;\n}\n\n/**\n * 带重试的异步函数执行器\n */\nasync function withRetry<T>(\n fn: () => Promise<T>,\n config: RetryConfig = {},\n serviceName: string\n): Promise<T> {\n const maxRetries = config.maxRetries ?? 3;\n const retryDelay = config.retryDelay ?? 1000;\n const exponentialBackoff = config.exponentialBackoff ?? true;\n\n let lastError: unknown;\n \n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n \n if (attempt < maxRetries) {\n const delay = exponentialBackoff \n ? retryDelay * Math.pow(2, attempt)\n : retryDelay;\n \n logger.warn(\n `${serviceName} 初始化失败(尝试 ${attempt + 1}/${maxRetries + 1}),${delay}ms 后重试...`,\n error\n );\n \n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n \n logger.error(`${serviceName} 初始化失败,已重试 ${maxRetries} 次`);\n throw lastError;\n}\n\n/**\n * 初始化所有服务\n * \n * 优化:\n * 1. 区分关键服务和非关键服务\n * 2. 关键服务并行初始化,缩短首屏时间\n * 3. 非关键服务延迟到应用渲染后初始化,使用 requestIdleCallback 在空闲时初始化\n * 4. 实现服务初始化失败重试机制,提高启动成功率\n * \n * @param options - 启动配置选项\n * @returns 服务初始化结果\n */\nexport async function initializeServices(\n options: StartOptions = {}\n): Promise<ServicesInitResult> {\n const startTime = performance.now();\n \n // 重试配置\n const retryConfig: RetryConfig = {\n maxRetries: options.serviceRetry?.maxRetries ?? 3,\n retryDelay: options.serviceRetry?.retryDelay ?? 1000,\n exponentialBackoff: options.serviceRetry?.exponentialBackoff ?? true,\n };\n\n // ========== 关键服务:必须在应用渲染前初始化 ==========\n // 这些服务是应用运行的基础,必须并行初始化完成\n\n // 1. 监控服务(必须最先初始化,因为其他服务可能依赖它)\n const monitoringPromise = withRetry(\n () => Promise.resolve(initMonitoring({\n ...options.errorMonitor,\n onError: (error) => {\n logger.error('监控服务捕获到错误:', error);\n options.errorMonitor?.onError?.(error);\n },\n })),\n retryConfig,\n '监控服务'\n );\n\n // 2. 存储服务(关键服务,应用可能需要立即使用存储)\n const storagePromise = withRetry(\n () => Promise.resolve().then(() => {\n storage.initialize(options.storageOptions);\n return storage;\n }),\n retryConfig,\n '存储服务'\n );\n\n // 3. 状态管理器(关键服务,应用状态管理的基础)\n const stateManagerPromise = withRetry(\n () => Promise.resolve().then(() => {\n if (options.stateManager !== undefined) {\n return new StateManager(options.stateManager);\n } else {\n // 默认初始化状态管理器\n return new StateManager({\n enableRegistry: true,\n defaultScope: 'app',\n });\n }\n }),\n retryConfig,\n '状态管理器'\n );\n\n // 4. 事件总线(关键服务,用于应用内部通信)\n const eventBusPromise = withRetry(\n () => Promise.resolve().then(() => {\n const eventBusConfig: AppEventBusConfig = {\n enableTracking: options.eventBus?.enableTracking ?? (process.env.NODE_ENV === 'development'),\n maxHistorySize: options.eventBus?.maxHistorySize ?? 100,\n enableValidation: options.eventBus?.enableValidation ?? false,\n enablePerformanceMonitoring: options.eventBus?.enablePerformanceMonitoring ?? (process.env.NODE_ENV === 'development'),\n namespacePrefix: options.eventBus?.namespacePrefix,\n instanceId: options.eventBus?.instanceId,\n enableSecurityMode: options.eventBus?.enableSecurityMode ?? false,\n allowedSources: options.eventBus?.allowedSources,\n };\n return new AppEventBus(eventBusConfig);\n }),\n retryConfig,\n '事件总线'\n );\n\n // 并行执行关键服务初始化\n const [monitoring, , stateManager, eventBus] = await Promise.all([\n monitoringPromise,\n storagePromise,\n stateManagerPromise,\n eventBusPromise,\n ]);\n\n logger.info('关键服务初始化完成');\n\n // 初始化性能监控(依赖监控服务,必须在监控服务初始化后)\n const performanceMonitor = new PerformanceMonitor({\n ...options.performanceMonitor,\n onReport: (metrics) => {\n monitoring.reportPerformance(metrics);\n options.performanceMonitor?.onReport?.(metrics);\n },\n });\n\n // 在页面卸载时清理性能监控\n if (typeof window !== 'undefined') {\n const cleanupHandler = () => {\n performanceMonitor.disconnect();\n window.removeEventListener('beforeunload', cleanupHandler);\n };\n window.addEventListener('beforeunload', cleanupHandler);\n }\n\n const criticalServicesDuration = performance.now() - startTime;\n logger.debug(`关键服务初始化完成,耗时: ${criticalServicesDuration.toFixed(2)}ms`);\n\n // ========== 非关键服务:延迟到应用渲染后初始化 ==========\n // 这些服务不影响首屏渲染,可以在空闲时初始化\n\n /**\n * 延迟初始化非关键服务\n * 在应用渲染后调用,使用 requestIdleCallback 在空闲时初始化\n */\n const initializeNonCriticalServices = async (): Promise<void> => {\n const nonCriticalStartTime = performance.now();\n \n // 使用 requestIdleCallback 在浏览器空闲时初始化非关键服务\n // 如果不支持 requestIdleCallback,则使用 setTimeout 延迟执行\n const scheduleInit = (callback: () => void) => {\n if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {\n window.requestIdleCallback(callback, { timeout: 5000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n return new Promise<void>((resolve) => {\n scheduleInit(async () => {\n try {\n // 1. 分析服务(可选,非关键)\n if (options.analytics) {\n try {\n await withRetry(\n () => import('../../utils/analytics').then(({ initAnalytics }) => {\n initAnalytics(options.analytics!);\n return true;\n }),\n retryConfig,\n '分析服务'\n );\n logger.debug('分析服务初始化完成');\n } catch (error) {\n logger.warn('分析服务初始化失败(不影响应用运行):', error);\n }\n }\n\n // 2. 运行时安全服务(可选,非关键)\n if (options.runtimeSecurity) {\n try {\n await withRetry(\n () => import('../../utils/runtimeSecurity').then(({ RuntimeSecurity }) => {\n RuntimeSecurity.initialize(options.runtimeSecurity!);\n return true;\n }),\n retryConfig,\n '运行时安全服务'\n );\n logger.debug('运行时安全服务初始化完成');\n } catch (error) {\n logger.warn('运行时安全服务初始化失败(不影响应用运行):', error);\n }\n }\n\n const nonCriticalDuration = performance.now() - nonCriticalStartTime;\n logger.debug(`非关键服务初始化完成,耗时: ${nonCriticalDuration.toFixed(2)}ms`);\n } catch (error) {\n logger.warn('非关键服务初始化过程中出现错误:', error);\n } finally {\n resolve();\n }\n });\n });\n };\n\n // 记录关键服务初始化性能指标\n if (monitoring.reportPerformance) {\n monitoring.reportPerformance({\n serviceInitDuration: criticalServicesDuration,\n } as any);\n }\n\n return {\n monitoring,\n performanceMonitor,\n stateManager,\n eventBus,\n initializeNonCriticalServices,\n };\n}\n"],"names":["logger","initMonitoring","PerformanceMonitor","storage","StateManager","AppEventBus","withRetry","fn","config","serviceName","maxRetries","retryDelay","exponentialBackoff","lastError","attempt","error","delay","Math","pow","warn","Promise","resolve","setTimeout","initializeServices","options","startTime","performance","now","retryConfig","serviceRetry","monitoringPromise","errorMonitor","onError","storagePromise","then","initialize","storageOptions","stateManagerPromise","stateManager","undefined","enableRegistry","defaultScope","eventBusPromise","eventBusConfig","enableTracking","eventBus","process","env","NODE_ENV","maxHistorySize","enableValidation","enablePerformanceMonitoring","namespacePrefix","instanceId","enableSecurityMode","allowedSources","monitoring","all","info","performanceMonitor","onReport","metrics","reportPerformance","window","cleanupHandler","disconnect","removeEventListener","addEventListener","criticalServicesDuration","debug","toFixed","initializeNonCriticalServices","nonCriticalStartTime","scheduleInit","callback","requestIdleCallback","timeout","analytics","initAnalytics","runtimeSecurity","RuntimeSecurity","nonCriticalDuration","serviceInitDuration"],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ const _app = require("../app");
|
|
|
18
18
|
const _error = require("../error");
|
|
19
19
|
const _initialization = require("../initialization");
|
|
20
20
|
const _splash = require("../splash");
|
|
21
|
-
const
|
|
21
|
+
const _utils = require("@vlian/utils");
|
|
22
22
|
const _RouterManager = require("../router/RouterManager");
|
|
23
23
|
const _reactrouterdom = require("react-router-dom");
|
|
24
24
|
function _define_property(obj, key, value) {
|
|
@@ -188,7 +188,7 @@ let AppRenderer = class AppRenderer {
|
|
|
188
188
|
Promise.resolve().then(()=>{
|
|
189
189
|
try {
|
|
190
190
|
const configStr = JSON.stringify(options);
|
|
191
|
-
const validation =
|
|
191
|
+
const validation = _utils.SecurityUtils.validateInput(configStr);
|
|
192
192
|
if (!validation.safe) {
|
|
193
193
|
services.monitoring.captureError(new Error('配置项包含不安全内容'), {
|
|
194
194
|
reason: validation.reason
|