@vlian/framework 1.1.1 → 1.2.1

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.
Files changed (44) hide show
  1. package/README.md +35 -1
  2. package/dist/core/config/ConfigLoader.cjs +90 -8
  3. package/dist/core/config/ConfigLoader.cjs.map +1 -1
  4. package/dist/core/config/ConfigLoader.d.ts +20 -4
  5. package/dist/core/config/ConfigLoader.d.ts.map +1 -1
  6. package/dist/core/config/ConfigLoader.js +90 -8
  7. package/dist/core/config/ConfigLoader.js.map +1 -1
  8. package/dist/core/error/ErrorBoundary.cjs +23 -9
  9. package/dist/core/error/ErrorBoundary.cjs.map +1 -1
  10. package/dist/core/error/ErrorBoundary.d.ts.map +1 -1
  11. package/dist/core/error/ErrorBoundary.js +23 -9
  12. package/dist/core/error/ErrorBoundary.js.map +1 -1
  13. package/dist/core/error/ErrorHandler.cjs +277 -0
  14. package/dist/core/error/ErrorHandler.cjs.map +1 -0
  15. package/dist/core/error/ErrorHandler.d.ts +172 -0
  16. package/dist/core/error/ErrorHandler.d.ts.map +1 -0
  17. package/dist/core/error/ErrorHandler.js +261 -0
  18. package/dist/core/error/ErrorHandler.js.map +1 -0
  19. package/dist/core/error/index.cjs +10 -0
  20. package/dist/core/error/index.cjs.map +1 -1
  21. package/dist/core/error/index.d.ts +2 -0
  22. package/dist/core/error/index.d.ts.map +1 -1
  23. package/dist/core/error/index.js +1 -0
  24. package/dist/core/error/index.js.map +1 -1
  25. package/dist/core/startup/initializeServices.cjs +69 -24
  26. package/dist/core/startup/initializeServices.cjs.map +1 -1
  27. package/dist/core/startup/initializeServices.d.ts +9 -2
  28. package/dist/core/startup/initializeServices.d.ts.map +1 -1
  29. package/dist/core/startup/initializeServices.js +73 -26
  30. package/dist/core/startup/initializeServices.js.map +1 -1
  31. package/dist/core/startup/renderApp.cjs +100 -61
  32. package/dist/core/startup/renderApp.cjs.map +1 -1
  33. package/dist/core/startup/renderApp.d.ts +2 -2
  34. package/dist/core/startup/renderApp.d.ts.map +1 -1
  35. package/dist/core/startup/renderApp.js +101 -62
  36. package/dist/core/startup/renderApp.js.map +1 -1
  37. package/dist/core/startup/startApp.cjs +7 -0
  38. package/dist/core/startup/startApp.cjs.map +1 -1
  39. package/dist/core/startup/startApp.d.ts.map +1 -1
  40. package/dist/core/startup/startApp.js +7 -0
  41. package/dist/core/startup/startApp.js.map +1 -1
  42. package/dist/index.umd.js +32434 -39284
  43. package/dist/index.umd.js.map +1 -1
  44. package/package.json +40 -6
@@ -75,6 +75,76 @@ function _interop_require_wildcard(obj, nodeInterop) {
75
75
  }
76
76
  return newObj;
77
77
  }
78
+ const OptimizedAppContent = /*#__PURE__*/ (0, _react.memo)(({ options, services, context, // securityConfig 用于未来扩展,当前暂不使用
79
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
80
+ securityConfig: _securityConfig })=>{
81
+ // 优化:使用 useMemo 缓存初始语言计算
82
+ const initialLocale = (0, _react.useMemo)(()=>{
83
+ return options.locale ? Object.keys(options.locale)[0] || 'zh-CN' : 'zh-CN';
84
+ }, [
85
+ options.locale
86
+ ]);
87
+ // 优化:使用 useMemo 缓存路由判断结果
88
+ const shouldUseRouter = (0, _react.useMemo)(()=>{
89
+ const routerEnabled = options.router ? options.router.enabled !== false && options.router.enabled !== 'disabled' : false;
90
+ if (!routerEnabled) {
91
+ return false;
92
+ }
93
+ const routerManager = (0, _RouterManager.getRouterManager)();
94
+ const router = routerManager.getRouter();
95
+ return router !== null;
96
+ }, [
97
+ options.router
98
+ ]);
99
+ // 优化:使用 useMemo 缓存路由实例
100
+ const router = (0, _react.useMemo)(()=>{
101
+ if (!shouldUseRouter) {
102
+ return null;
103
+ }
104
+ const routerManager = (0, _RouterManager.getRouterManager)();
105
+ return routerManager.getRouter();
106
+ }, [
107
+ shouldUseRouter
108
+ ]);
109
+ // 优化:使用 useCallback 缓存错误处理函数
110
+ const handleError = (0, _react.useCallback)((error)=>{
111
+ services.monitoring.captureError(error);
112
+ }, [
113
+ services.monitoring
114
+ ]);
115
+ // 优化:使用 useMemo 缓存应用内容
116
+ const appContent = (0, _react.useMemo)(()=>{
117
+ if (shouldUseRouter && router) {
118
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_reactrouterdom.RouterProvider, {
119
+ router: router
120
+ });
121
+ }
122
+ return options.app || /*#__PURE__*/ (0, _jsxruntime.jsx)(_app.DefaultApp, {});
123
+ }, [
124
+ shouldUseRouter,
125
+ router,
126
+ options.app
127
+ ]);
128
+ return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_error.ErrorBoundary, {
129
+ fallback: options.errorFallback,
130
+ onError: handleError,
131
+ children: [
132
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_initialization.InitializationErrorThrower, {}),
133
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_app.AppContextProvider, {
134
+ initialTheme: options.theme,
135
+ initialLocale: initialLocale,
136
+ initialAntdConfig: options.antd,
137
+ initialInitializationContext: context,
138
+ stateManager: services.stateManager,
139
+ antdApp: options.antdApp,
140
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_app.BasicLayout, {
141
+ children: appContent
142
+ })
143
+ })
144
+ ]
145
+ });
146
+ });
147
+ OptimizedAppContent.displayName = 'OptimizedAppContent';
78
148
  let AppRenderer = class AppRenderer {
79
149
  /**
80
150
  * 初始化渲染器
@@ -92,8 +162,8 @@ let AppRenderer = class AppRenderer {
92
162
  *
93
163
  * 优化:
94
164
  * 1. 默认启用安全防护(XSS防护)
95
- * 2. 优化组件渲染性能
96
- * 3. 缓存计算结果,避免重复计算
165
+ * 2. 优化组件渲染性能,使用 useMemo 缓存计算结果
166
+ * 3. 将安全配置计算提取到初始化阶段
97
167
  *
98
168
  * @param options - 启动配置选项
99
169
  * @param services - 服务实例
@@ -102,30 +172,19 @@ let AppRenderer = class AppRenderer {
102
172
  if (!this.root) {
103
173
  throw new Error('渲染器未初始化,请先调用 initialize()');
104
174
  }
105
- // 获取初始语言(从 locale 配置中推断,或使用默认值)
106
- const initialLocale = options.locale ? Object.keys(options.locale)[0] || 'zh-CN' : 'zh-CN';
107
- // 检查路由是否已启用
108
- // 路由启用的条件:配置了 router 且 enabled !== false 且 enabled !== 'disabled'
109
- const routerEnabled = options.router ? options.router.enabled !== false && options.router.enabled !== 'disabled' : false;
110
- // 检查路由管理器是否已初始化(运行时状态)
111
- const routerManager = (0, _RouterManager.getRouterManager)();
112
- const router = routerManager.getRouter();
113
- // const isRouterInitialized = routerManager.isRouterEnabled();
114
- // 如果路由已启用且已初始化,使用 RouterProvider(路由系统接管渲染)
115
- // 否则直接渲染应用内容(不使用路由系统)
116
- const shouldUseRouter = routerEnabled && router !== null;
117
- // 安全性增强:应用默认安全策略
118
- // 默认启用 XSS 防护、配置验证和用户输入清理
175
+ // 优化:安全配置在初始化阶段计算(在 startApp 中预计算)
176
+ // 这里只使用预计算的值,避免在渲染时重复计算
119
177
  const securityConfig = {
120
178
  enableXSSProtection: options.security?.enableXSSProtection ?? true,
121
179
  validateConfig: options.security?.validateConfig ?? true,
122
180
  sanitizeUserInput: options.security?.sanitizeUserInput ?? true,
123
181
  csrf: options.security?.csrf
124
182
  };
183
+ // 优化:安全验证在初始化阶段完成,这里只进行必要的运行时检查
125
184
  // 如果启用了安全模式(默认启用),对配置进行验证
126
- if (securityConfig.enableXSSProtection) {
127
- if (securityConfig.validateConfig) {
128
- // 验证配置项中可能包含的字符串内容
185
+ if (securityConfig.enableXSSProtection && securityConfig.validateConfig) {
186
+ // 异步验证配置,不阻塞渲染
187
+ Promise.resolve().then(()=>{
129
188
  try {
130
189
  const configStr = JSON.stringify(options);
131
190
  const validation = _security.SecurityUtils.validateInput(configStr);
@@ -137,51 +196,31 @@ let AppRenderer = class AppRenderer {
137
196
  } catch (error) {
138
197
  // 忽略序列化错误(某些配置项可能包含不可序列化的内容)
139
198
  }
140
- }
141
- // 初始化 CSRF 防护(如果启用)
142
- if (securityConfig.csrf?.enabled !== false) {
143
- // 异步初始化 CSRF,但不阻塞渲染
144
- Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../utils/csrf"))).then(({ initCSRFManager })=>{
145
- initCSRFManager({
146
- headerName: securityConfig.csrf?.headerName,
147
- cookieName: securityConfig.csrf?.cookieName,
148
- getToken: securityConfig.csrf?.getToken,
149
- validateToken: securityConfig.csrf?.validateToken
150
- });
151
- }).catch((error)=>{
152
- // CSRF 初始化失败不影响应用启动,但记录警告
153
- if (process.env.NODE_ENV === 'development') {
154
- console.warn('CSRF 防护初始化失败:', error);
155
- }
199
+ });
200
+ }
201
+ // 初始化 CSRF 防护(如果启用,异步执行,不阻塞渲染)
202
+ if (securityConfig.enableXSSProtection && securityConfig.csrf?.enabled !== false) {
203
+ Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../../utils/csrf"))).then(({ initCSRFManager })=>{
204
+ initCSRFManager({
205
+ headerName: securityConfig.csrf?.headerName,
206
+ cookieName: securityConfig.csrf?.cookieName,
207
+ getToken: securityConfig.csrf?.getToken,
208
+ validateToken: securityConfig.csrf?.validateToken
156
209
  });
157
- }
210
+ }).catch((error)=>{
211
+ // CSRF 初始化失败不影响应用启动,但记录警告
212
+ if (process.env.NODE_ENV === 'development') {
213
+ console.warn('CSRF 防护初始化失败:', error);
214
+ }
215
+ });
158
216
  }
159
- // 优化:缓存错误处理函数,避免每次渲染都创建新函数
160
- const handleError = (error)=>{
161
- services.monitoring.captureError(error);
162
- };
217
+ // 使用优化的应用内容组件,内部使用 useMemo 缓存计算结果
163
218
  this.root.render(/*#__PURE__*/ (0, _jsxruntime.jsx)(_react.StrictMode, {
164
- children: /*#__PURE__*/ (0, _jsxruntime.jsxs)(_error.ErrorBoundary, {
165
- fallback: options.errorFallback,
166
- onError: handleError,
167
- children: [
168
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_initialization.InitializationErrorThrower, {}),
169
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_app.AppContextProvider, {
170
- initialTheme: options.theme,
171
- initialLocale: initialLocale,
172
- initialAntdConfig: options.antd,
173
- initialInitializationContext: context,
174
- stateManager: services.stateManager,
175
- antdApp: options.antdApp,
176
- children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_app.BasicLayout, {
177
- children: shouldUseRouter ? // 启用路由时,使用 RouterProvider(路由内容由路由配置决定)
178
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_reactrouterdom.RouterProvider, {
179
- router: router
180
- }) : // 未启用路由时,直接渲染应用内容
181
- options.app || /*#__PURE__*/ (0, _jsxruntime.jsx)(_app.DefaultApp, {})
182
- })
183
- })
184
- ]
219
+ children: /*#__PURE__*/ (0, _jsxruntime.jsx)(OptimizedAppContent, {
220
+ options: options,
221
+ services: services,
222
+ context: context,
223
+ securityConfig: securityConfig
185
224
  })
186
225
  }));
187
226
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/startup/renderApp.tsx"],"sourcesContent":["/**\n * 应用渲染模块\n * 负责渲染React应用\n */\n\nimport { createRoot } from 'react-dom/client';\nimport type { Root } from 'react-dom/client';\nimport { StrictMode } from 'react';\nimport type { Container, RootOptions } from 'react-dom/client';\nimport { BasicLayout, DefaultApp, AppContextProvider } from '../app';\nimport type { LangType } from '../../library/locale/types';\nimport { ErrorBoundary } from '../error';\nimport { InitializationErrorThrower } from '../initialization';\nimport type { StartOptions } from '../types';\nimport type { InitializationContext } from '../initialization';\nimport type { MonitoringService } from '../../utils/monitoring';\nimport type { StateManager } from '../../state';\nimport { SplashScreen } from '../splash';\nimport { SecurityUtils } from '../../utils/security';\nimport { getRouterManager } from '../router/RouterManager';\nimport { RouterProvider } from \"react-router-dom\";\n\n/**\n * 应用渲染器\n */\nexport class AppRenderer {\n private root: Root | null = null;\n private container: Container | null = null;\n\n /**\n * 初始化渲染器\n * \n * @param container - React应用的挂载容器\n * @param rootOptions - React根节点配置选项\n */\n initialize(container: Container, rootOptions?: RootOptions): void {\n this.container = container;\n if (!this.root) {\n this.root = createRoot(container, rootOptions);\n }\n }\n\n /**\n * 渲染应用\n * \n * 优化:\n * 1. 默认启用安全防护(XSS防护)\n * 2. 优化组件渲染性能\n * 3. 缓存计算结果,避免重复计算\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param context - 初始化上下文(可选)\n */\n async renderApp(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n context?: InitializationContext\n ): Promise<void> {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 获取初始语言(从 locale 配置中推断,或使用默认值)\n const initialLocale: LangType = options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n\n // 检查路由是否已启用\n // 路由启用的条件:配置了 router 且 enabled !== false 且 enabled !== 'disabled'\n const routerEnabled = options.router\n ? options.router.enabled !== false && options.router.enabled !== 'disabled'\n : false;\n \n // 检查路由管理器是否已初始化(运行时状态)\n const routerManager = getRouterManager();\n const router = routerManager.getRouter();\n // const isRouterInitialized = routerManager.isRouterEnabled();\n\n // 如果路由已启用且已初始化,使用 RouterProvider(路由系统接管渲染)\n // 否则直接渲染应用内容(不使用路由系统)\n const shouldUseRouter = routerEnabled && router !== null;\n\n // 安全性增强:应用默认安全策略\n // 默认启用 XSS 防护、配置验证和用户输入清理\n const securityConfig = {\n enableXSSProtection: options.security?.enableXSSProtection ?? true,\n validateConfig: options.security?.validateConfig ?? true,\n sanitizeUserInput: options.security?.sanitizeUserInput ?? true,\n csrf: options.security?.csrf,\n };\n\n // 如果启用了安全模式(默认启用),对配置进行验证\n if (securityConfig.enableXSSProtection) {\n if (securityConfig.validateConfig) {\n // 验证配置项中可能包含的字符串内容\n try {\n const configStr = JSON.stringify(options);\n const validation = SecurityUtils.validateInput(configStr);\n if (!validation.safe) {\n services.monitoring.captureError(\n new Error('配置项包含不安全内容'),\n { reason: validation.reason }\n );\n }\n } catch (error) {\n // 忽略序列化错误(某些配置项可能包含不可序列化的内容)\n }\n }\n\n // 初始化 CSRF 防护(如果启用)\n if (securityConfig.csrf?.enabled !== false) {\n // 异步初始化 CSRF,但不阻塞渲染\n import('../../utils/csrf').then(({ initCSRFManager }) => {\n initCSRFManager({\n headerName: securityConfig.csrf?.headerName,\n cookieName: securityConfig.csrf?.cookieName,\n getToken: securityConfig.csrf?.getToken,\n validateToken: securityConfig.csrf?.validateToken,\n });\n }).catch((error) => {\n // CSRF 初始化失败不影响应用启动,但记录警告\n if (process.env.NODE_ENV === 'development') {\n console.warn('CSRF 防护初始化失败:', error);\n }\n });\n }\n }\n\n // 优化:缓存错误处理函数,避免每次渲染都创建新函数\n const handleError = (error: unknown) => {\n services.monitoring.captureError(error);\n };\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={handleError}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n initialInitializationContext={context}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n <BasicLayout>\n {shouldUseRouter ? (\n // 启用路由时,使用 RouterProvider(路由内容由路由配置决定)\n <RouterProvider router={router} />\n ) : (\n // 未启用路由时,直接渲染应用内容\n options.app || <DefaultApp />\n )}\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 渲染启动页\n * \n * 注意:启动页不使用 RouterWrapper,因为启动页应该在路由系统之前渲染\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param onComplete - 启动页完成回调\n */\n renderSplashScreen(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n onComplete: (context: InitializationContext) => void\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 获取初始语言(从 locale 配置中推断,或使用默认值)\n const initialLocale: LangType = options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(error) => {\n services.monitoring.captureError(error);\n }}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n {/* \n 启动页不使用 RouterWrapper,因为:\n 1. 启动页应该在路由系统初始化之前渲染\n 2. 启动页完成后才会渲染主应用,此时路由系统已经初始化完成\n */}\n <BasicLayout>\n <SplashScreen options={options} onComplete={onComplete} />\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 渲染错误页面\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param error - 错误信息\n */\n renderError(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n }\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(err) => {\n services.monitoring.captureError(err);\n if (options.errorMonitor?.onError) {\n options.errorMonitor.onError(err);\n }\n }}\n >\n <InitializationErrorThrower />\n <div>框架启动失败</div>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 销毁渲染器\n */\n destroy(): void {\n if (this.root) {\n this.root.unmount();\n this.root = null;\n }\n this.container = null;\n }\n\n /**\n * 获取容器\n */\n getContainer(): Container | null {\n return this.container;\n }\n}\n"],"names":["AppRenderer","initialize","container","rootOptions","root","createRoot","renderApp","options","services","context","Error","initialLocale","locale","Object","keys","routerEnabled","router","enabled","routerManager","getRouterManager","getRouter","shouldUseRouter","securityConfig","enableXSSProtection","security","validateConfig","sanitizeUserInput","csrf","configStr","JSON","stringify","validation","SecurityUtils","validateInput","safe","monitoring","captureError","reason","error","then","initCSRFManager","headerName","cookieName","getToken","validateToken","catch","process","env","NODE_ENV","console","warn","handleError","render","StrictMode","ErrorBoundary","fallback","errorFallback","onError","InitializationErrorThrower","AppContextProvider","initialTheme","theme","initialAntdConfig","antd","initialInitializationContext","stateManager","antdApp","BasicLayout","RouterProvider","app","DefaultApp","renderSplashScreen","onComplete","SplashScreen","renderError","err","errorMonitor","div","destroy","unmount","getContainer"],"mappings":"AAAA;;;CAGC;;;;+BAsBYA;;;eAAAA;;;;wBApBc;uBAEA;qBAEiC;uBAE9B;gCACa;wBAKd;0BACC;+BACG;gCACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKxB,IAAA,AAAMA,cAAN,MAAMA;IAIX;;;;;GAKC,GACDC,WAAWC,SAAoB,EAAEC,WAAyB,EAAQ;QAChE,IAAI,CAACD,SAAS,GAAGA;QACjB,IAAI,CAAC,IAAI,CAACE,IAAI,EAAE;YACd,IAAI,CAACA,IAAI,GAAGC,IAAAA,kBAAU,EAACH,WAAWC;QACpC;IACF;IAEA;;;;;;;;;;;GAWC,GACD,MAAMG,UACJC,OAAqB,EACrBC,QAGC,EACDC,OAA+B,EAChB;QACf,IAAI,CAAC,IAAI,CAACL,IAAI,EAAE;YACd,MAAM,IAAIM,MAAM;QAClB;QAEA,gCAAgC;QAChC,MAAMC,gBAA0BJ,QAAQK,MAAM,GAC1C,AAACC,OAAOC,IAAI,CAACP,QAAQK,MAAM,CAAC,CAAC,EAAE,IAAiB,UAChD;QAEJ,YAAY;QACZ,kEAAkE;QAClE,MAAMG,gBAAgBR,QAAQS,MAAM,GAChCT,QAAQS,MAAM,CAACC,OAAO,KAAK,SAASV,QAAQS,MAAM,CAACC,OAAO,KAAK,aAC/D;QAEJ,uBAAuB;QACvB,MAAMC,gBAAgBC,IAAAA,+BAAgB;QACtC,MAAMH,SAASE,cAAcE,SAAS;QACtC,+DAA+D;QAE/D,2CAA2C;QAC3C,sBAAsB;QACtB,MAAMC,kBAAkBN,iBAAiBC,WAAW;QAEpD,iBAAiB;QACjB,0BAA0B;QAC1B,MAAMM,iBAAiB;YACrBC,qBAAqBhB,QAAQiB,QAAQ,EAAED,uBAAuB;YAC9DE,gBAAgBlB,QAAQiB,QAAQ,EAAEC,kBAAkB;YACpDC,mBAAmBnB,QAAQiB,QAAQ,EAAEE,qBAAqB;YAC1DC,MAAMpB,QAAQiB,QAAQ,EAAEG;QAC1B;QAEA,0BAA0B;QAC1B,IAAIL,eAAeC,mBAAmB,EAAE;YACtC,IAAID,eAAeG,cAAc,EAAE;gBACjC,mBAAmB;gBACnB,IAAI;oBACF,MAAMG,YAAYC,KAAKC,SAAS,CAACvB;oBACjC,MAAMwB,aAAaC,uBAAa,CAACC,aAAa,CAACL;oBAC/C,IAAI,CAACG,WAAWG,IAAI,EAAE;wBACpB1B,SAAS2B,UAAU,CAACC,YAAY,CAC9B,IAAI1B,MAAM,eACV;4BAAE2B,QAAQN,WAAWM,MAAM;wBAAC;oBAEhC;gBACF,EAAE,OAAOC,OAAO;gBACd,6BAA6B;gBAC/B;YACF;YAEA,oBAAoB;YACpB,IAAIhB,eAAeK,IAAI,EAAEV,YAAY,OAAO;gBAC1C,oBAAoB;gBACpB,mEAAA,QAAO,sBAAoBsB,IAAI,CAAC,CAAC,EAAEC,eAAe,EAAE;oBAClDA,gBAAgB;wBACdC,YAAYnB,eAAeK,IAAI,EAAEc;wBACjCC,YAAYpB,eAAeK,IAAI,EAAEe;wBACjCC,UAAUrB,eAAeK,IAAI,EAAEgB;wBAC/BC,eAAetB,eAAeK,IAAI,EAAEiB;oBACtC;gBACF,GAAGC,KAAK,CAAC,CAACP;oBACR,0BAA0B;oBAC1B,IAAIQ,QAAQC,GAAG,CAACC,QAAQ,KAAK,eAAe;wBAC1CC,QAAQC,IAAI,CAAC,iBAAiBZ;oBAChC;gBACF;YACF;QACF;QAEA,2BAA2B;QAC3B,MAAMa,cAAc,CAACb;YACnB9B,SAAS2B,UAAU,CAACC,YAAY,CAACE;QACnC;QAEA,IAAI,CAAClC,IAAI,CAACgD,MAAM,eACd,qBAACC,iBAAU;sBACT,cAAA,sBAACC,oBAAa;gBACZC,UAAUhD,QAAQiD,aAAa;gBAC/BC,SAASN;;kCAET,qBAACO,0CAA0B;kCAC3B,qBAACC,uBAAkB;wBACjBC,cAAcrD,QAAQsD,KAAK;wBAC3BlD,eAAeA;wBACfmD,mBAAmBvD,QAAQwD,IAAI;wBAC/BC,8BAA8BvD;wBAC9BwD,cAAczD,SAASyD,YAAY;wBACnCC,SAAS3D,QAAQ2D,OAAO;kCAExB,cAAA,qBAACC,gBAAW;sCACT9C,kBACC,uCAAuC;0CACvC,qBAAC+C,8BAAc;gCAACpD,QAAQA;iCAExB,kBAAkB;4BAClBT,QAAQ8D,GAAG,kBAAI,qBAACC,eAAU;;;;;;IAOxC;IAEA;;;;;;;;GAQC,GACDC,mBACEhE,OAAqB,EACrBC,QAGC,EACDgE,UAAoD,EAC9C;QACN,IAAI,CAAC,IAAI,CAACpE,IAAI,EAAE;YACd,MAAM,IAAIM,MAAM;QAClB;QAEA,gCAAgC;QAChC,MAAMC,gBAA0BJ,QAAQK,MAAM,GAC1C,AAACC,OAAOC,IAAI,CAACP,QAAQK,MAAM,CAAC,CAAC,EAAE,IAAiB,UAChD;QAEJ,IAAI,CAACR,IAAI,CAACgD,MAAM,eACd,qBAACC,iBAAU;sBACT,cAAA,sBAACC,oBAAa;gBACZC,UAAUhD,QAAQiD,aAAa;gBAC/BC,SAAS,CAACnB;oBACR9B,SAAS2B,UAAU,CAACC,YAAY,CAACE;gBACnC;;kCAEA,qBAACoB,0CAA0B;kCAC3B,qBAACC,uBAAkB;wBACjBC,cAAcrD,QAAQsD,KAAK;wBAC3BlD,eAAeA;wBACfmD,mBAAmBvD,QAAQwD,IAAI;wBAC/BE,cAAczD,SAASyD,YAAY;wBACnCC,SAAS3D,QAAQ2D,OAAO;kCAOxB,cAAA,qBAACC,gBAAW;sCACV,cAAA,qBAACM,oBAAY;gCAAClE,SAASA;gCAASiE,YAAYA;;;;;;;IAMxD;IAEA;;;;;;GAMC,GACDE,YACEnE,OAAqB,EACrBC,QAEC,EACK;QACN,IAAI,CAAC,IAAI,CAACJ,IAAI,EAAE;YACd,MAAM,IAAIM,MAAM;QAClB;QAEA,IAAI,CAACN,IAAI,CAACgD,MAAM,eACd,qBAACC,iBAAU;sBACT,cAAA,sBAACC,oBAAa;gBACZC,UAAUhD,QAAQiD,aAAa;gBAC/BC,SAAS,CAACkB;oBACRnE,SAAS2B,UAAU,CAACC,YAAY,CAACuC;oBACjC,IAAIpE,QAAQqE,YAAY,EAAEnB,SAAS;wBACjClD,QAAQqE,YAAY,CAACnB,OAAO,CAACkB;oBAC/B;gBACF;;kCAEA,qBAACjB,0CAA0B;kCAC3B,qBAACmB;kCAAI;;;;;IAIb;IAEA;;GAEC,GACDC,UAAgB;QACd,IAAI,IAAI,CAAC1E,IAAI,EAAE;YACb,IAAI,CAACA,IAAI,CAAC2E,OAAO;YACjB,IAAI,CAAC3E,IAAI,GAAG;QACd;QACA,IAAI,CAACF,SAAS,GAAG;IACnB;IAEA;;GAEC,GACD8E,eAAiC;QAC/B,OAAO,IAAI,CAAC9E,SAAS;IACvB;;QAxPA,uBAAQE,QAAoB;QAC5B,uBAAQF,aAA8B;;AAwPxC"}
1
+ {"version":3,"sources":["../../../src/core/startup/renderApp.tsx"],"sourcesContent":["/**\n * 应用渲染模块\n * 负责渲染React应用\n */\n\nimport { createRoot } from 'react-dom/client';\nimport type { Root } from 'react-dom/client';\nimport { StrictMode, useMemo, useCallback, memo } from 'react';\nimport type { Container, RootOptions } from 'react-dom/client';\nimport { BasicLayout, DefaultApp, AppContextProvider } from '../app';\nimport type { LangType } from '../../library/locale/types';\nimport { ErrorBoundary } from '../error';\nimport { InitializationErrorThrower } from '../initialization';\nimport type { StartOptions } from '../types';\nimport type { InitializationContext } from '../initialization';\nimport type { MonitoringService } from '../../utils/monitoring';\nimport type { StateManager } from '../../state';\nimport { SplashScreen } from '../splash';\nimport { SecurityUtils } from '../../utils/security';\nimport { getRouterManager } from '../router/RouterManager';\nimport { RouterProvider } from \"react-router-dom\";\n\n/**\n * 安全配置类型\n */\ninterface SecurityConfig {\n enableXSSProtection: boolean;\n validateConfig: boolean;\n sanitizeUserInput: boolean;\n csrf?: StartOptions['security'] extends infer S\n ? S extends { csrf?: infer C }\n ? C\n : never\n : never;\n}\n\n/**\n * 优化的应用内容组件\n * 使用 useMemo 缓存计算结果,提升渲染性能\n */\ninterface OptimizedAppContentProps {\n options: StartOptions;\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n };\n context?: InitializationContext;\n securityConfig: SecurityConfig;\n}\n\nconst OptimizedAppContent = memo<OptimizedAppContentProps>(({\n options,\n services,\n context,\n // securityConfig 用于未来扩展,当前暂不使用\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n securityConfig: _securityConfig,\n}) => {\n // 优化:使用 useMemo 缓存初始语言计算\n const initialLocale = useMemo<LangType>(() => {\n return options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n }, [options.locale]);\n\n // 优化:使用 useMemo 缓存路由判断结果\n const shouldUseRouter = useMemo(() => {\n const routerEnabled = options.router\n ? options.router.enabled !== false && options.router.enabled !== 'disabled'\n : false;\n \n if (!routerEnabled) {\n return false;\n }\n \n const routerManager = getRouterManager();\n const router = routerManager.getRouter();\n return router !== null;\n }, [options.router]);\n\n // 优化:使用 useMemo 缓存路由实例\n const router = useMemo(() => {\n if (!shouldUseRouter) {\n return null;\n }\n const routerManager = getRouterManager();\n return routerManager.getRouter();\n }, [shouldUseRouter]);\n\n // 优化:使用 useCallback 缓存错误处理函数\n const handleError = useCallback((error: unknown) => {\n services.monitoring.captureError(error);\n }, [services.monitoring]);\n\n // 优化:使用 useMemo 缓存应用内容\n const appContent = useMemo(() => {\n if (shouldUseRouter && router) {\n return <RouterProvider router={router} />;\n }\n return options.app || <DefaultApp />;\n }, [shouldUseRouter, router, options.app]);\n\n return (\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={handleError}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n initialInitializationContext={context}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n <BasicLayout>\n {appContent}\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n );\n});\n\nOptimizedAppContent.displayName = 'OptimizedAppContent';\n\n/**\n * 应用渲染器\n */\nexport class AppRenderer {\n private root: Root | null = null;\n private container: Container | null = null;\n\n /**\n * 初始化渲染器\n * \n * @param container - React应用的挂载容器\n * @param rootOptions - React根节点配置选项\n */\n initialize(container: Container, rootOptions?: RootOptions): void {\n this.container = container;\n if (!this.root) {\n this.root = createRoot(container, rootOptions);\n }\n }\n\n /**\n * 渲染应用\n * \n * 优化:\n * 1. 默认启用安全防护(XSS防护)\n * 2. 优化组件渲染性能,使用 useMemo 缓存计算结果\n * 3. 将安全配置计算提取到初始化阶段\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param context - 初始化上下文(可选)\n */\n async renderApp(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n context?: InitializationContext\n ): Promise<void> {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 优化:安全配置在初始化阶段计算(在 startApp 中预计算)\n // 这里只使用预计算的值,避免在渲染时重复计算\n const securityConfig: SecurityConfig = {\n enableXSSProtection: options.security?.enableXSSProtection ?? true,\n validateConfig: options.security?.validateConfig ?? true,\n sanitizeUserInput: options.security?.sanitizeUserInput ?? true,\n csrf: options.security?.csrf,\n };\n\n // 优化:安全验证在初始化阶段完成,这里只进行必要的运行时检查\n // 如果启用了安全模式(默认启用),对配置进行验证\n if (securityConfig.enableXSSProtection && securityConfig.validateConfig) {\n // 异步验证配置,不阻塞渲染\n Promise.resolve().then(() => {\n try {\n const configStr = JSON.stringify(options);\n const validation = SecurityUtils.validateInput(configStr);\n if (!validation.safe) {\n services.monitoring.captureError(\n new Error('配置项包含不安全内容'),\n { reason: validation.reason }\n );\n }\n } catch (error) {\n // 忽略序列化错误(某些配置项可能包含不可序列化的内容)\n }\n });\n }\n\n // 初始化 CSRF 防护(如果启用,异步执行,不阻塞渲染)\n if (securityConfig.enableXSSProtection && securityConfig.csrf?.enabled !== false) {\n import('../../utils/csrf').then(({ initCSRFManager }) => {\n initCSRFManager({\n headerName: securityConfig.csrf?.headerName,\n cookieName: securityConfig.csrf?.cookieName,\n getToken: securityConfig.csrf?.getToken,\n validateToken: securityConfig.csrf?.validateToken,\n });\n }).catch((error) => {\n // CSRF 初始化失败不影响应用启动,但记录警告\n if (process.env.NODE_ENV === 'development') {\n console.warn('CSRF 防护初始化失败:', error);\n }\n });\n }\n\n // 使用优化的应用内容组件,内部使用 useMemo 缓存计算结果\n this.root.render(\n <StrictMode>\n <OptimizedAppContent\n options={options}\n services={services}\n context={context}\n securityConfig={securityConfig}\n />\n </StrictMode>\n );\n }\n\n /**\n * 渲染启动页\n * \n * 注意:启动页不使用 RouterWrapper,因为启动页应该在路由系统之前渲染\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param onComplete - 启动页完成回调\n */\n renderSplashScreen(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n onComplete: (context: InitializationContext) => void\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 获取初始语言(从 locale 配置中推断,或使用默认值)\n const initialLocale: LangType = options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(error) => {\n services.monitoring.captureError(error);\n }}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n {/* \n 启动页不使用 RouterWrapper,因为:\n 1. 启动页应该在路由系统初始化之前渲染\n 2. 启动页完成后才会渲染主应用,此时路由系统已经初始化完成\n */}\n <BasicLayout>\n <SplashScreen options={options} onComplete={onComplete} />\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 渲染错误页面\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param error - 错误信息\n */\n renderError(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n }\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(err) => {\n services.monitoring.captureError(err);\n if (options.errorMonitor?.onError) {\n options.errorMonitor.onError(err);\n }\n }}\n >\n <InitializationErrorThrower />\n <div>框架启动失败</div>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 销毁渲染器\n */\n destroy(): void {\n if (this.root) {\n this.root.unmount();\n this.root = null;\n }\n this.container = null;\n }\n\n /**\n * 获取容器\n */\n getContainer(): Container | null {\n return this.container;\n }\n}\n"],"names":["AppRenderer","OptimizedAppContent","memo","options","services","context","securityConfig","_securityConfig","initialLocale","useMemo","locale","Object","keys","shouldUseRouter","routerEnabled","router","enabled","routerManager","getRouterManager","getRouter","handleError","useCallback","error","monitoring","captureError","appContent","RouterProvider","app","DefaultApp","ErrorBoundary","fallback","errorFallback","onError","InitializationErrorThrower","AppContextProvider","initialTheme","theme","initialAntdConfig","antd","initialInitializationContext","stateManager","antdApp","BasicLayout","displayName","initialize","container","rootOptions","root","createRoot","renderApp","Error","enableXSSProtection","security","validateConfig","sanitizeUserInput","csrf","Promise","resolve","then","configStr","JSON","stringify","validation","SecurityUtils","validateInput","safe","reason","initCSRFManager","headerName","cookieName","getToken","validateToken","catch","process","env","NODE_ENV","console","warn","render","StrictMode","renderSplashScreen","onComplete","SplashScreen","renderError","err","errorMonitor","div","destroy","unmount","getContainer"],"mappings":"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"}
@@ -25,8 +25,8 @@ export declare class AppRenderer {
25
25
  *
26
26
  * 优化:
27
27
  * 1. 默认启用安全防护(XSS防护)
28
- * 2. 优化组件渲染性能
29
- * 3. 缓存计算结果,避免重复计算
28
+ * 2. 优化组件渲染性能,使用 useMemo 缓存计算结果
29
+ * 3. 将安全配置计算提取到初始化阶段
30
30
  *
31
31
  * @param options - 启动配置选项
32
32
  * @param services - 服务实例
@@ -1 +1 @@
1
- {"version":3,"file":"renderApp.d.ts","sourceRoot":"","sources":["../../../src/core/startup/renderApp.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,SAAS,CAA0B;IAE3C;;;;;OAKG;IACH,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI;IAOjE;;;;;;;;;;;OAWG;IACG,SAAS,CACb,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE;QACR,UAAU,EAAE,iBAAiB,CAAC;QAC9B,YAAY,EAAE,YAAY,CAAC;KAC5B,EACD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,IAAI,CAAC;IA0GhB;;;;;;;;OAQG;IACH,kBAAkB,CAChB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE;QACR,UAAU,EAAE,iBAAiB,CAAC;QAC9B,YAAY,EAAE,YAAY,CAAC;KAC5B,EACD,UAAU,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,IAAI,GACnD,IAAI;IAwCP;;;;;;OAMG;IACH,WAAW,CACT,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE;QACR,UAAU,EAAE,iBAAiB,CAAC;KAC/B,GACA,IAAI;IAuBP;;OAEG;IACH,OAAO,IAAI,IAAI;IAQf;;OAEG;IACH,YAAY,IAAI,SAAS,GAAG,IAAI;CAGjC"}
1
+ {"version":3,"file":"renderApp.d.ts","sourceRoot":"","sources":["../../../src/core/startup/renderApp.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA8GhD;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,SAAS,CAA0B;IAE3C;;;;;OAKG;IACH,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI;IAOjE;;;;;;;;;;;OAWG;IACG,SAAS,CACb,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE;QACR,UAAU,EAAE,iBAAiB,CAAC;QAC9B,YAAY,EAAE,YAAY,CAAC;KAC5B,EACD,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,IAAI,CAAC;IAgEhB;;;;;;;;OAQG;IACH,kBAAkB,CAChB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE;QACR,UAAU,EAAE,iBAAiB,CAAC;QAC9B,YAAY,EAAE,YAAY,CAAC;KAC5B,EACD,UAAU,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,IAAI,GACnD,IAAI;IAwCP;;;;;;OAMG;IACH,WAAW,CACT,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE;QACR,UAAU,EAAE,iBAAiB,CAAC;KAC/B,GACA,IAAI;IAuBP;;OAEG;IACH,OAAO,IAAI,IAAI;IAQf;;OAEG;IACH,YAAY,IAAI,SAAS,GAAG,IAAI;CAGjC"}
@@ -16,7 +16,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  * 应用渲染模块
17
17
  * 负责渲染React应用
18
18
  */ import { createRoot } from "react-dom/client";
19
- import { StrictMode } from "react";
19
+ import { StrictMode, useMemo, useCallback, memo } from "react";
20
20
  import { BasicLayout, DefaultApp, AppContextProvider } from "../app";
21
21
  import { ErrorBoundary } from "../error";
22
22
  import { InitializationErrorThrower } from "../initialization";
@@ -24,6 +24,76 @@ import { SplashScreen } from "../splash";
24
24
  import { SecurityUtils } from "../../utils/security";
25
25
  import { getRouterManager } from "../router/RouterManager";
26
26
  import { RouterProvider } from "react-router-dom";
27
+ const OptimizedAppContent = /*#__PURE__*/ memo(({ options, services, context, // securityConfig 用于未来扩展,当前暂不使用
28
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
29
+ securityConfig: _securityConfig })=>{
30
+ // 优化:使用 useMemo 缓存初始语言计算
31
+ const initialLocale = useMemo(()=>{
32
+ return options.locale ? Object.keys(options.locale)[0] || 'zh-CN' : 'zh-CN';
33
+ }, [
34
+ options.locale
35
+ ]);
36
+ // 优化:使用 useMemo 缓存路由判断结果
37
+ const shouldUseRouter = useMemo(()=>{
38
+ const routerEnabled = options.router ? options.router.enabled !== false && options.router.enabled !== 'disabled' : false;
39
+ if (!routerEnabled) {
40
+ return false;
41
+ }
42
+ const routerManager = getRouterManager();
43
+ const router = routerManager.getRouter();
44
+ return router !== null;
45
+ }, [
46
+ options.router
47
+ ]);
48
+ // 优化:使用 useMemo 缓存路由实例
49
+ const router = useMemo(()=>{
50
+ if (!shouldUseRouter) {
51
+ return null;
52
+ }
53
+ const routerManager = getRouterManager();
54
+ return routerManager.getRouter();
55
+ }, [
56
+ shouldUseRouter
57
+ ]);
58
+ // 优化:使用 useCallback 缓存错误处理函数
59
+ const handleError = useCallback((error)=>{
60
+ services.monitoring.captureError(error);
61
+ }, [
62
+ services.monitoring
63
+ ]);
64
+ // 优化:使用 useMemo 缓存应用内容
65
+ const appContent = useMemo(()=>{
66
+ if (shouldUseRouter && router) {
67
+ return /*#__PURE__*/ _jsx(RouterProvider, {
68
+ router: router
69
+ });
70
+ }
71
+ return options.app || /*#__PURE__*/ _jsx(DefaultApp, {});
72
+ }, [
73
+ shouldUseRouter,
74
+ router,
75
+ options.app
76
+ ]);
77
+ return /*#__PURE__*/ _jsxs(ErrorBoundary, {
78
+ fallback: options.errorFallback,
79
+ onError: handleError,
80
+ children: [
81
+ /*#__PURE__*/ _jsx(InitializationErrorThrower, {}),
82
+ /*#__PURE__*/ _jsx(AppContextProvider, {
83
+ initialTheme: options.theme,
84
+ initialLocale: initialLocale,
85
+ initialAntdConfig: options.antd,
86
+ initialInitializationContext: context,
87
+ stateManager: services.stateManager,
88
+ antdApp: options.antdApp,
89
+ children: /*#__PURE__*/ _jsx(BasicLayout, {
90
+ children: appContent
91
+ })
92
+ })
93
+ ]
94
+ });
95
+ });
96
+ OptimizedAppContent.displayName = 'OptimizedAppContent';
27
97
  /**
28
98
  * 应用渲染器
29
99
  */ export class AppRenderer {
@@ -43,8 +113,8 @@ import { RouterProvider } from "react-router-dom";
43
113
  *
44
114
  * 优化:
45
115
  * 1. 默认启用安全防护(XSS防护)
46
- * 2. 优化组件渲染性能
47
- * 3. 缓存计算结果,避免重复计算
116
+ * 2. 优化组件渲染性能,使用 useMemo 缓存计算结果
117
+ * 3. 将安全配置计算提取到初始化阶段
48
118
  *
49
119
  * @param options - 启动配置选项
50
120
  * @param services - 服务实例
@@ -53,30 +123,19 @@ import { RouterProvider } from "react-router-dom";
53
123
  if (!this.root) {
54
124
  throw new Error('渲染器未初始化,请先调用 initialize()');
55
125
  }
56
- // 获取初始语言(从 locale 配置中推断,或使用默认值)
57
- const initialLocale = options.locale ? Object.keys(options.locale)[0] || 'zh-CN' : 'zh-CN';
58
- // 检查路由是否已启用
59
- // 路由启用的条件:配置了 router 且 enabled !== false 且 enabled !== 'disabled'
60
- const routerEnabled = options.router ? options.router.enabled !== false && options.router.enabled !== 'disabled' : false;
61
- // 检查路由管理器是否已初始化(运行时状态)
62
- const routerManager = getRouterManager();
63
- const router = routerManager.getRouter();
64
- // const isRouterInitialized = routerManager.isRouterEnabled();
65
- // 如果路由已启用且已初始化,使用 RouterProvider(路由系统接管渲染)
66
- // 否则直接渲染应用内容(不使用路由系统)
67
- const shouldUseRouter = routerEnabled && router !== null;
68
- // 安全性增强:应用默认安全策略
69
- // 默认启用 XSS 防护、配置验证和用户输入清理
126
+ // 优化:安全配置在初始化阶段计算(在 startApp 中预计算)
127
+ // 这里只使用预计算的值,避免在渲染时重复计算
70
128
  const securityConfig = {
71
129
  enableXSSProtection: options.security?.enableXSSProtection ?? true,
72
130
  validateConfig: options.security?.validateConfig ?? true,
73
131
  sanitizeUserInput: options.security?.sanitizeUserInput ?? true,
74
132
  csrf: options.security?.csrf
75
133
  };
134
+ // 优化:安全验证在初始化阶段完成,这里只进行必要的运行时检查
76
135
  // 如果启用了安全模式(默认启用),对配置进行验证
77
- if (securityConfig.enableXSSProtection) {
78
- if (securityConfig.validateConfig) {
79
- // 验证配置项中可能包含的字符串内容
136
+ if (securityConfig.enableXSSProtection && securityConfig.validateConfig) {
137
+ // 异步验证配置,不阻塞渲染
138
+ Promise.resolve().then(()=>{
80
139
  try {
81
140
  const configStr = JSON.stringify(options);
82
141
  const validation = SecurityUtils.validateInput(configStr);
@@ -88,51 +147,31 @@ import { RouterProvider } from "react-router-dom";
88
147
  } catch (error) {
89
148
  // 忽略序列化错误(某些配置项可能包含不可序列化的内容)
90
149
  }
91
- }
92
- // 初始化 CSRF 防护(如果启用)
93
- if (securityConfig.csrf?.enabled !== false) {
94
- // 异步初始化 CSRF,但不阻塞渲染
95
- import("../../utils/csrf").then(({ initCSRFManager })=>{
96
- initCSRFManager({
97
- headerName: securityConfig.csrf?.headerName,
98
- cookieName: securityConfig.csrf?.cookieName,
99
- getToken: securityConfig.csrf?.getToken,
100
- validateToken: securityConfig.csrf?.validateToken
101
- });
102
- }).catch((error)=>{
103
- // CSRF 初始化失败不影响应用启动,但记录警告
104
- if (process.env.NODE_ENV === 'development') {
105
- console.warn('CSRF 防护初始化失败:', error);
106
- }
150
+ });
151
+ }
152
+ // 初始化 CSRF 防护(如果启用,异步执行,不阻塞渲染)
153
+ if (securityConfig.enableXSSProtection && securityConfig.csrf?.enabled !== false) {
154
+ import("../../utils/csrf").then(({ initCSRFManager })=>{
155
+ initCSRFManager({
156
+ headerName: securityConfig.csrf?.headerName,
157
+ cookieName: securityConfig.csrf?.cookieName,
158
+ getToken: securityConfig.csrf?.getToken,
159
+ validateToken: securityConfig.csrf?.validateToken
107
160
  });
108
- }
161
+ }).catch((error)=>{
162
+ // CSRF 初始化失败不影响应用启动,但记录警告
163
+ if (process.env.NODE_ENV === 'development') {
164
+ console.warn('CSRF 防护初始化失败:', error);
165
+ }
166
+ });
109
167
  }
110
- // 优化:缓存错误处理函数,避免每次渲染都创建新函数
111
- const handleError = (error)=>{
112
- services.monitoring.captureError(error);
113
- };
168
+ // 使用优化的应用内容组件,内部使用 useMemo 缓存计算结果
114
169
  this.root.render(/*#__PURE__*/ _jsx(StrictMode, {
115
- children: /*#__PURE__*/ _jsxs(ErrorBoundary, {
116
- fallback: options.errorFallback,
117
- onError: handleError,
118
- children: [
119
- /*#__PURE__*/ _jsx(InitializationErrorThrower, {}),
120
- /*#__PURE__*/ _jsx(AppContextProvider, {
121
- initialTheme: options.theme,
122
- initialLocale: initialLocale,
123
- initialAntdConfig: options.antd,
124
- initialInitializationContext: context,
125
- stateManager: services.stateManager,
126
- antdApp: options.antdApp,
127
- children: /*#__PURE__*/ _jsx(BasicLayout, {
128
- children: shouldUseRouter ? // 启用路由时,使用 RouterProvider(路由内容由路由配置决定)
129
- /*#__PURE__*/ _jsx(RouterProvider, {
130
- router: router
131
- }) : // 未启用路由时,直接渲染应用内容
132
- options.app || /*#__PURE__*/ _jsx(DefaultApp, {})
133
- })
134
- })
135
- ]
170
+ children: /*#__PURE__*/ _jsx(OptimizedAppContent, {
171
+ options: options,
172
+ services: services,
173
+ context: context,
174
+ securityConfig: securityConfig
136
175
  })
137
176
  }));
138
177
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/startup/renderApp.tsx"],"sourcesContent":["/**\n * 应用渲染模块\n * 负责渲染React应用\n */\n\nimport { createRoot } from 'react-dom/client';\nimport type { Root } from 'react-dom/client';\nimport { StrictMode } from 'react';\nimport type { Container, RootOptions } from 'react-dom/client';\nimport { BasicLayout, DefaultApp, AppContextProvider } from '../app';\nimport type { LangType } from '../../library/locale/types';\nimport { ErrorBoundary } from '../error';\nimport { InitializationErrorThrower } from '../initialization';\nimport type { StartOptions } from '../types';\nimport type { InitializationContext } from '../initialization';\nimport type { MonitoringService } from '../../utils/monitoring';\nimport type { StateManager } from '../../state';\nimport { SplashScreen } from '../splash';\nimport { SecurityUtils } from '../../utils/security';\nimport { getRouterManager } from '../router/RouterManager';\nimport { RouterProvider } from \"react-router-dom\";\n\n/**\n * 应用渲染器\n */\nexport class AppRenderer {\n private root: Root | null = null;\n private container: Container | null = null;\n\n /**\n * 初始化渲染器\n * \n * @param container - React应用的挂载容器\n * @param rootOptions - React根节点配置选项\n */\n initialize(container: Container, rootOptions?: RootOptions): void {\n this.container = container;\n if (!this.root) {\n this.root = createRoot(container, rootOptions);\n }\n }\n\n /**\n * 渲染应用\n * \n * 优化:\n * 1. 默认启用安全防护(XSS防护)\n * 2. 优化组件渲染性能\n * 3. 缓存计算结果,避免重复计算\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param context - 初始化上下文(可选)\n */\n async renderApp(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n context?: InitializationContext\n ): Promise<void> {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 获取初始语言(从 locale 配置中推断,或使用默认值)\n const initialLocale: LangType = options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n\n // 检查路由是否已启用\n // 路由启用的条件:配置了 router 且 enabled !== false 且 enabled !== 'disabled'\n const routerEnabled = options.router\n ? options.router.enabled !== false && options.router.enabled !== 'disabled'\n : false;\n \n // 检查路由管理器是否已初始化(运行时状态)\n const routerManager = getRouterManager();\n const router = routerManager.getRouter();\n // const isRouterInitialized = routerManager.isRouterEnabled();\n\n // 如果路由已启用且已初始化,使用 RouterProvider(路由系统接管渲染)\n // 否则直接渲染应用内容(不使用路由系统)\n const shouldUseRouter = routerEnabled && router !== null;\n\n // 安全性增强:应用默认安全策略\n // 默认启用 XSS 防护、配置验证和用户输入清理\n const securityConfig = {\n enableXSSProtection: options.security?.enableXSSProtection ?? true,\n validateConfig: options.security?.validateConfig ?? true,\n sanitizeUserInput: options.security?.sanitizeUserInput ?? true,\n csrf: options.security?.csrf,\n };\n\n // 如果启用了安全模式(默认启用),对配置进行验证\n if (securityConfig.enableXSSProtection) {\n if (securityConfig.validateConfig) {\n // 验证配置项中可能包含的字符串内容\n try {\n const configStr = JSON.stringify(options);\n const validation = SecurityUtils.validateInput(configStr);\n if (!validation.safe) {\n services.monitoring.captureError(\n new Error('配置项包含不安全内容'),\n { reason: validation.reason }\n );\n }\n } catch (error) {\n // 忽略序列化错误(某些配置项可能包含不可序列化的内容)\n }\n }\n\n // 初始化 CSRF 防护(如果启用)\n if (securityConfig.csrf?.enabled !== false) {\n // 异步初始化 CSRF,但不阻塞渲染\n import('../../utils/csrf').then(({ initCSRFManager }) => {\n initCSRFManager({\n headerName: securityConfig.csrf?.headerName,\n cookieName: securityConfig.csrf?.cookieName,\n getToken: securityConfig.csrf?.getToken,\n validateToken: securityConfig.csrf?.validateToken,\n });\n }).catch((error) => {\n // CSRF 初始化失败不影响应用启动,但记录警告\n if (process.env.NODE_ENV === 'development') {\n console.warn('CSRF 防护初始化失败:', error);\n }\n });\n }\n }\n\n // 优化:缓存错误处理函数,避免每次渲染都创建新函数\n const handleError = (error: unknown) => {\n services.monitoring.captureError(error);\n };\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={handleError}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n initialInitializationContext={context}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n <BasicLayout>\n {shouldUseRouter ? (\n // 启用路由时,使用 RouterProvider(路由内容由路由配置决定)\n <RouterProvider router={router} />\n ) : (\n // 未启用路由时,直接渲染应用内容\n options.app || <DefaultApp />\n )}\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 渲染启动页\n * \n * 注意:启动页不使用 RouterWrapper,因为启动页应该在路由系统之前渲染\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param onComplete - 启动页完成回调\n */\n renderSplashScreen(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n onComplete: (context: InitializationContext) => void\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 获取初始语言(从 locale 配置中推断,或使用默认值)\n const initialLocale: LangType = options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(error) => {\n services.monitoring.captureError(error);\n }}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n {/* \n 启动页不使用 RouterWrapper,因为:\n 1. 启动页应该在路由系统初始化之前渲染\n 2. 启动页完成后才会渲染主应用,此时路由系统已经初始化完成\n */}\n <BasicLayout>\n <SplashScreen options={options} onComplete={onComplete} />\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 渲染错误页面\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param error - 错误信息\n */\n renderError(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n }\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(err) => {\n services.monitoring.captureError(err);\n if (options.errorMonitor?.onError) {\n options.errorMonitor.onError(err);\n }\n }}\n >\n <InitializationErrorThrower />\n <div>框架启动失败</div>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 销毁渲染器\n */\n destroy(): void {\n if (this.root) {\n this.root.unmount();\n this.root = null;\n }\n this.container = null;\n }\n\n /**\n * 获取容器\n */\n getContainer(): Container | null {\n return this.container;\n }\n}\n"],"names":["createRoot","StrictMode","BasicLayout","DefaultApp","AppContextProvider","ErrorBoundary","InitializationErrorThrower","SplashScreen","SecurityUtils","getRouterManager","RouterProvider","AppRenderer","initialize","container","rootOptions","root","renderApp","options","services","context","Error","initialLocale","locale","Object","keys","routerEnabled","router","enabled","routerManager","getRouter","shouldUseRouter","securityConfig","enableXSSProtection","security","validateConfig","sanitizeUserInput","csrf","configStr","JSON","stringify","validation","validateInput","safe","monitoring","captureError","reason","error","then","initCSRFManager","headerName","cookieName","getToken","validateToken","catch","process","env","NODE_ENV","console","warn","handleError","render","fallback","errorFallback","onError","initialTheme","theme","initialAntdConfig","antd","initialInitializationContext","stateManager","antdApp","app","renderSplashScreen","onComplete","renderError","err","errorMonitor","div","destroy","unmount","getContainer"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/core/startup/renderApp.tsx"],"sourcesContent":["/**\n * 应用渲染模块\n * 负责渲染React应用\n */\n\nimport { createRoot } from 'react-dom/client';\nimport type { Root } from 'react-dom/client';\nimport { StrictMode, useMemo, useCallback, memo } from 'react';\nimport type { Container, RootOptions } from 'react-dom/client';\nimport { BasicLayout, DefaultApp, AppContextProvider } from '../app';\nimport type { LangType } from '../../library/locale/types';\nimport { ErrorBoundary } from '../error';\nimport { InitializationErrorThrower } from '../initialization';\nimport type { StartOptions } from '../types';\nimport type { InitializationContext } from '../initialization';\nimport type { MonitoringService } from '../../utils/monitoring';\nimport type { StateManager } from '../../state';\nimport { SplashScreen } from '../splash';\nimport { SecurityUtils } from '../../utils/security';\nimport { getRouterManager } from '../router/RouterManager';\nimport { RouterProvider } from \"react-router-dom\";\n\n/**\n * 安全配置类型\n */\ninterface SecurityConfig {\n enableXSSProtection: boolean;\n validateConfig: boolean;\n sanitizeUserInput: boolean;\n csrf?: StartOptions['security'] extends infer S\n ? S extends { csrf?: infer C }\n ? C\n : never\n : never;\n}\n\n/**\n * 优化的应用内容组件\n * 使用 useMemo 缓存计算结果,提升渲染性能\n */\ninterface OptimizedAppContentProps {\n options: StartOptions;\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n };\n context?: InitializationContext;\n securityConfig: SecurityConfig;\n}\n\nconst OptimizedAppContent = memo<OptimizedAppContentProps>(({\n options,\n services,\n context,\n // securityConfig 用于未来扩展,当前暂不使用\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n securityConfig: _securityConfig,\n}) => {\n // 优化:使用 useMemo 缓存初始语言计算\n const initialLocale = useMemo<LangType>(() => {\n return options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n }, [options.locale]);\n\n // 优化:使用 useMemo 缓存路由判断结果\n const shouldUseRouter = useMemo(() => {\n const routerEnabled = options.router\n ? options.router.enabled !== false && options.router.enabled !== 'disabled'\n : false;\n \n if (!routerEnabled) {\n return false;\n }\n \n const routerManager = getRouterManager();\n const router = routerManager.getRouter();\n return router !== null;\n }, [options.router]);\n\n // 优化:使用 useMemo 缓存路由实例\n const router = useMemo(() => {\n if (!shouldUseRouter) {\n return null;\n }\n const routerManager = getRouterManager();\n return routerManager.getRouter();\n }, [shouldUseRouter]);\n\n // 优化:使用 useCallback 缓存错误处理函数\n const handleError = useCallback((error: unknown) => {\n services.monitoring.captureError(error);\n }, [services.monitoring]);\n\n // 优化:使用 useMemo 缓存应用内容\n const appContent = useMemo(() => {\n if (shouldUseRouter && router) {\n return <RouterProvider router={router} />;\n }\n return options.app || <DefaultApp />;\n }, [shouldUseRouter, router, options.app]);\n\n return (\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={handleError}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n initialInitializationContext={context}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n <BasicLayout>\n {appContent}\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n );\n});\n\nOptimizedAppContent.displayName = 'OptimizedAppContent';\n\n/**\n * 应用渲染器\n */\nexport class AppRenderer {\n private root: Root | null = null;\n private container: Container | null = null;\n\n /**\n * 初始化渲染器\n * \n * @param container - React应用的挂载容器\n * @param rootOptions - React根节点配置选项\n */\n initialize(container: Container, rootOptions?: RootOptions): void {\n this.container = container;\n if (!this.root) {\n this.root = createRoot(container, rootOptions);\n }\n }\n\n /**\n * 渲染应用\n * \n * 优化:\n * 1. 默认启用安全防护(XSS防护)\n * 2. 优化组件渲染性能,使用 useMemo 缓存计算结果\n * 3. 将安全配置计算提取到初始化阶段\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param context - 初始化上下文(可选)\n */\n async renderApp(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n context?: InitializationContext\n ): Promise<void> {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 优化:安全配置在初始化阶段计算(在 startApp 中预计算)\n // 这里只使用预计算的值,避免在渲染时重复计算\n const securityConfig: SecurityConfig = {\n enableXSSProtection: options.security?.enableXSSProtection ?? true,\n validateConfig: options.security?.validateConfig ?? true,\n sanitizeUserInput: options.security?.sanitizeUserInput ?? true,\n csrf: options.security?.csrf,\n };\n\n // 优化:安全验证在初始化阶段完成,这里只进行必要的运行时检查\n // 如果启用了安全模式(默认启用),对配置进行验证\n if (securityConfig.enableXSSProtection && securityConfig.validateConfig) {\n // 异步验证配置,不阻塞渲染\n Promise.resolve().then(() => {\n try {\n const configStr = JSON.stringify(options);\n const validation = SecurityUtils.validateInput(configStr);\n if (!validation.safe) {\n services.monitoring.captureError(\n new Error('配置项包含不安全内容'),\n { reason: validation.reason }\n );\n }\n } catch (error) {\n // 忽略序列化错误(某些配置项可能包含不可序列化的内容)\n }\n });\n }\n\n // 初始化 CSRF 防护(如果启用,异步执行,不阻塞渲染)\n if (securityConfig.enableXSSProtection && securityConfig.csrf?.enabled !== false) {\n import('../../utils/csrf').then(({ initCSRFManager }) => {\n initCSRFManager({\n headerName: securityConfig.csrf?.headerName,\n cookieName: securityConfig.csrf?.cookieName,\n getToken: securityConfig.csrf?.getToken,\n validateToken: securityConfig.csrf?.validateToken,\n });\n }).catch((error) => {\n // CSRF 初始化失败不影响应用启动,但记录警告\n if (process.env.NODE_ENV === 'development') {\n console.warn('CSRF 防护初始化失败:', error);\n }\n });\n }\n\n // 使用优化的应用内容组件,内部使用 useMemo 缓存计算结果\n this.root.render(\n <StrictMode>\n <OptimizedAppContent\n options={options}\n services={services}\n context={context}\n securityConfig={securityConfig}\n />\n </StrictMode>\n );\n }\n\n /**\n * 渲染启动页\n * \n * 注意:启动页不使用 RouterWrapper,因为启动页应该在路由系统之前渲染\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param onComplete - 启动页完成回调\n */\n renderSplashScreen(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n stateManager: StateManager;\n },\n onComplete: (context: InitializationContext) => void\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n // 获取初始语言(从 locale 配置中推断,或使用默认值)\n const initialLocale: LangType = options.locale\n ? (Object.keys(options.locale)[0] as LangType) || 'zh-CN'\n : 'zh-CN';\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(error) => {\n services.monitoring.captureError(error);\n }}\n >\n <InitializationErrorThrower />\n <AppContextProvider\n initialTheme={options.theme}\n initialLocale={initialLocale}\n initialAntdConfig={options.antd}\n stateManager={services.stateManager}\n antdApp={options.antdApp}\n >\n {/* \n 启动页不使用 RouterWrapper,因为:\n 1. 启动页应该在路由系统初始化之前渲染\n 2. 启动页完成后才会渲染主应用,此时路由系统已经初始化完成\n */}\n <BasicLayout>\n <SplashScreen options={options} onComplete={onComplete} />\n </BasicLayout>\n </AppContextProvider>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 渲染错误页面\n * \n * @param options - 启动配置选项\n * @param services - 服务实例\n * @param error - 错误信息\n */\n renderError(\n options: StartOptions,\n services: {\n monitoring: MonitoringService;\n }\n ): void {\n if (!this.root) {\n throw new Error('渲染器未初始化,请先调用 initialize()');\n }\n\n this.root.render(\n <StrictMode>\n <ErrorBoundary\n fallback={options.errorFallback}\n onError={(err) => {\n services.monitoring.captureError(err);\n if (options.errorMonitor?.onError) {\n options.errorMonitor.onError(err);\n }\n }}\n >\n <InitializationErrorThrower />\n <div>框架启动失败</div>\n </ErrorBoundary>\n </StrictMode>\n );\n }\n\n /**\n * 销毁渲染器\n */\n destroy(): void {\n if (this.root) {\n this.root.unmount();\n this.root = null;\n }\n this.container = null;\n }\n\n /**\n * 获取容器\n */\n getContainer(): Container | null {\n return this.container;\n }\n}\n"],"names":["createRoot","StrictMode","useMemo","useCallback","memo","BasicLayout","DefaultApp","AppContextProvider","ErrorBoundary","InitializationErrorThrower","SplashScreen","SecurityUtils","getRouterManager","RouterProvider","OptimizedAppContent","options","services","context","securityConfig","_securityConfig","initialLocale","locale","Object","keys","shouldUseRouter","routerEnabled","router","enabled","routerManager","getRouter","handleError","error","monitoring","captureError","appContent","app","fallback","errorFallback","onError","initialTheme","theme","initialAntdConfig","antd","initialInitializationContext","stateManager","antdApp","displayName","AppRenderer","initialize","container","rootOptions","root","renderApp","Error","enableXSSProtection","security","validateConfig","sanitizeUserInput","csrf","Promise","resolve","then","configStr","JSON","stringify","validation","validateInput","safe","reason","initCSRFManager","headerName","cookieName","getToken","validateToken","catch","process","env","NODE_ENV","console","warn","render","renderSplashScreen","onComplete","renderError","err","errorMonitor","div","destroy","unmount","getContainer"],"mappings":"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"}
@@ -88,6 +88,13 @@ async function startApp(options = {}, instanceId) {
88
88
  if (frameworkEventManager) {
89
89
  frameworkEventManager.emitAppRenderComplete(finalInstanceId, renderDuration);
90
90
  }
91
+ // 优化:在应用渲染完成后,延迟初始化非关键服务
92
+ // 使用 requestIdleCallback 在浏览器空闲时初始化,不影响用户体验
93
+ if (services.initializeNonCriticalServices) {
94
+ services.initializeNonCriticalServices().catch((error)=>{
95
+ _utils.logger.warn('非关键服务初始化失败(不影响应用运行):', error);
96
+ });
97
+ }
91
98
  if (performanceTracker) {
92
99
  performanceTracker.recordFirstRender(renderDuration);
93
100
  const totalDuration = performance.now() - startTime;