@vlian/framework 1.1.0 → 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 (80) 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 -39098
  43. package/dist/index.umd.js.map +1 -1
  44. package/dist/request/core/RequestClient.cjs +20 -1
  45. package/dist/request/core/RequestClient.cjs.map +1 -1
  46. package/dist/request/core/RequestClient.d.ts +8 -0
  47. package/dist/request/core/RequestClient.d.ts.map +1 -1
  48. package/dist/request/core/RequestClient.js +20 -1
  49. package/dist/request/core/RequestClient.js.map +1 -1
  50. package/dist/request/index.cjs +3 -0
  51. package/dist/request/index.cjs.map +1 -1
  52. package/dist/request/index.d.ts +2 -2
  53. package/dist/request/index.d.ts.map +1 -1
  54. package/dist/request/index.js +1 -1
  55. package/dist/request/index.js.map +1 -1
  56. package/dist/request/plugin/index.cjs +4 -0
  57. package/dist/request/plugin/index.cjs.map +1 -1
  58. package/dist/request/plugin/index.d.ts +1 -0
  59. package/dist/request/plugin/index.d.ts.map +1 -1
  60. package/dist/request/plugin/index.js +1 -0
  61. package/dist/request/plugin/index.js.map +1 -1
  62. package/dist/request/plugin/queue.cjs +140 -0
  63. package/dist/request/plugin/queue.cjs.map +1 -0
  64. package/dist/request/plugin/queue.d.ts +92 -0
  65. package/dist/request/plugin/queue.d.ts.map +1 -0
  66. package/dist/request/plugin/queue.js +156 -0
  67. package/dist/request/plugin/queue.js.map +1 -0
  68. package/dist/request/utils/RequestQueueManager.cjs +168 -0
  69. package/dist/request/utils/RequestQueueManager.cjs.map +1 -0
  70. package/dist/request/utils/RequestQueueManager.d.ts +75 -0
  71. package/dist/request/utils/RequestQueueManager.d.ts.map +1 -0
  72. package/dist/request/utils/RequestQueueManager.js +160 -0
  73. package/dist/request/utils/RequestQueueManager.js.map +1 -0
  74. package/dist/request/utils/index.cjs +4 -0
  75. package/dist/request/utils/index.cjs.map +1 -1
  76. package/dist/request/utils/index.d.ts +1 -0
  77. package/dist/request/utils/index.d.ts.map +1 -1
  78. package/dist/request/utils/index.js +1 -0
  79. package/dist/request/utils/index.js.map +1 -1
  80. package/package.json +40 -6
package/README.md CHANGED
@@ -87,6 +87,40 @@ await startApp({
87
87
  });
88
88
  ```
89
89
 
90
+ ## 按需导入
91
+
92
+ 框架支持按需导入(Tree Shaking),可以显著减少打包体积。你可以使用子路径导入来只导入需要的模块:
93
+
94
+ ```typescript
95
+ // 只导入核心启动功能
96
+ import { startApp } from '@vlian/framework/core';
97
+
98
+ // 只导入工具函数
99
+ import { logger, LogLevel } from '@vlian/framework/utils';
100
+
101
+ // 只导入状态管理
102
+ import { StateManager } from '@vlian/framework/state';
103
+
104
+ // 只导入请求库
105
+ import { createRequestClient } from '@vlian/framework/request';
106
+
107
+ // 只导入国际化
108
+ import { setupI18n, $t } from '@vlian/framework/library';
109
+ ```
110
+
111
+ ### 可用的子路径
112
+
113
+ - `@vlian/framework/core` - 核心模块(启动、上下文、路由等)
114
+ - `@vlian/framework/utils` - 工具模块(日志、验证、安全等)
115
+ - `@vlian/framework/state` - 状态管理模块
116
+ - `@vlian/framework/library` - 基础库模块(国际化、存储等)
117
+ - `@vlian/framework/request` - 请求库模块
118
+ - `@vlian/framework/components` - 组件模块(当前为空)
119
+
120
+ ### 打包体积优化
121
+
122
+ 使用按需导入可以减少 30-50% 的打包体积,具体取决于你使用的功能。详细说明请查看 [按需导入使用指南](./docs/general/按需导入使用指南.md)。
123
+
90
124
  ## 核心模块
91
125
 
92
126
  ### Core 模块
@@ -122,7 +156,7 @@ await startApp({
122
156
 
123
157
  ## 许可证
124
158
 
125
- ISC
159
+ Apache-2.0
126
160
 
127
161
  ## 相关链接
128
162
 
@@ -21,11 +21,64 @@ _export(exports, {
21
21
  }
22
22
  });
23
23
  const _utils = require("../../utils");
24
+ function _define_property(obj, key, value) {
25
+ if (key in obj) {
26
+ Object.defineProperty(obj, key, {
27
+ value: value,
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true
31
+ });
32
+ } else {
33
+ obj[key] = value;
34
+ }
35
+ return obj;
36
+ }
24
37
  var ConfigFileFormat = /*#__PURE__*/ function(ConfigFileFormat) {
25
38
  ConfigFileFormat["JSON"] = "json";
26
39
  ConfigFileFormat["YAML"] = "yaml";
27
40
  return ConfigFileFormat;
28
41
  }({});
42
+ /**
43
+ * 配置变更通知管理器
44
+ */ let ConfigChangeNotifier = class ConfigChangeNotifier {
45
+ /**
46
+ * 添加配置变更监听器
47
+ */ addListener(listener) {
48
+ this.listeners.add(listener);
49
+ // 返回取消监听的函数
50
+ return ()=>{
51
+ this.listeners.delete(listener);
52
+ };
53
+ }
54
+ /**
55
+ * 移除配置变更监听器
56
+ */ removeListener(listener) {
57
+ this.listeners.delete(listener);
58
+ }
59
+ /**
60
+ * 通知配置变更
61
+ */ notify(newConfig, oldConfig) {
62
+ this.listeners.forEach((listener)=>{
63
+ try {
64
+ listener(newConfig, oldConfig);
65
+ } catch (error) {
66
+ _utils.logger.warn('配置变更监听器执行失败:', error);
67
+ }
68
+ });
69
+ }
70
+ /**
71
+ * 清除所有监听器
72
+ */ clear() {
73
+ this.listeners.clear();
74
+ }
75
+ constructor(){
76
+ _define_property(this, "listeners", new Set());
77
+ }
78
+ };
79
+ /**
80
+ * 全局配置变更通知器实例
81
+ */ const configChangeNotifier = new ConfigChangeNotifier();
29
82
  let ConfigLoader = class ConfigLoader {
30
83
  /**
31
84
  * 从JSON文件加载配置
@@ -217,27 +270,56 @@ let ConfigLoader = class ConfigLoader {
217
270
  /**
218
271
  * 从多个源加载配置(包括环境变量)
219
272
  *
220
- * 优先级(从低到高):
273
+ * 优化:明确优先级,从低到高:
221
274
  * 1. 默认配置
222
275
  * 2. 配置文件
223
276
  * 3. 环境变量
224
- * 4. 代码配置
277
+ * 4. 代码配置(通过 sources 参数传入)
225
278
  *
226
- * @param sources - 配置源列表
279
+ * @param sources - 配置源列表(代码配置,优先级最高)
280
+ * @param defaultConfig - 默认配置(优先级最低)
227
281
  * @param includeEnv - 是否包含环境变量,默认为 true
228
282
  * @param envPrefix - 环境变量前缀,默认为 'FRAMEWORK_'
229
283
  * @returns 合并后的配置
230
- */ static async loadFromAllSources(sources, includeEnv = true, envPrefix = 'FRAMEWORK_') {
231
- let merged = {};
232
- // 1. 加载配置文件
233
- merged = await this.loadFromMultipleSources(sources);
234
- // 2. 加载环境变量(优先级高于配置文件)
284
+ */ static async loadFromAllSources(sources = [], defaultConfig = {}, includeEnv = true, envPrefix = 'FRAMEWORK_') {
285
+ // 保存旧配置用于变更通知
286
+ const oldConfig = {
287
+ ...defaultConfig
288
+ };
289
+ // 1. 从默认配置开始
290
+ let merged = {
291
+ ...defaultConfig
292
+ };
293
+ // 2. 加载配置文件(优先级高于默认配置)
294
+ const fileConfigs = await this.loadFromMultipleSources(sources.filter((source)=>typeof source === 'object' && 'path' in source));
295
+ merged = this.mergeConfig(merged, fileConfigs);
296
+ // 3. 加载环境变量(优先级高于配置文件)
235
297
  if (includeEnv) {
236
298
  const envConfig = this.loadFromEnv(envPrefix);
237
299
  merged = this.mergeConfig(merged, envConfig);
238
300
  }
301
+ // 4. 合并代码配置(优先级最高)
302
+ const codeConfigs = sources.filter((source)=>typeof source === 'object' && !('path' in source));
303
+ for (const codeConfig of codeConfigs){
304
+ merged = this.mergeConfig(merged, codeConfig);
305
+ }
306
+ // 通知配置变更
307
+ configChangeNotifier.notify(merged, oldConfig);
239
308
  return merged;
240
309
  }
310
+ /**
311
+ * 添加配置变更监听器
312
+ *
313
+ * @param listener - 配置变更监听器
314
+ * @returns 取消监听的函数
315
+ */ static onConfigChange(listener) {
316
+ return configChangeNotifier.addListener(listener);
317
+ }
318
+ /**
319
+ * 移除配置变更监听器
320
+ */ static removeConfigChangeListener(listener) {
321
+ configChangeNotifier.removeListener(listener);
322
+ }
241
323
  };
242
324
 
243
325
  //# sourceMappingURL=ConfigLoader.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/config/ConfigLoader.ts"],"sourcesContent":["/**\n * 配置文件加载模块\n * 支持从JSON/YAML文件加载配置\n * 优化:支持环境变量配置、配置热更新\n */\n\nimport { logger } from '../../utils';\nimport type { StartOptions } from '../types';\n\n/**\n * 配置文件格式\n */\nexport enum ConfigFileFormat {\n JSON = 'json',\n YAML = 'yaml',\n}\n\n/**\n * 配置文件加载选项\n */\nexport interface ConfigFileLoadOptions {\n /**\n * 配置文件路径\n */\n path?: string;\n\n /**\n * 配置文件格式\n */\n format?: ConfigFileFormat;\n\n /**\n * 是否必需(如果为false,文件不存在时不报错)\n */\n required?: boolean;\n\n /**\n * 默认配置(文件不存在时使用)\n */\n defaultConfig?: Partial<StartOptions>;\n}\n\n/**\n * 配置加载器\n */\nexport class ConfigLoader {\n /**\n * 从JSON文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromJSON(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n return await response.json();\n }\n\n // 在Node.js环境中,使用fs模块\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const content = fs.readFileSync(path, 'utf-8');\n return JSON.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载JSON配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从YAML文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromYAML(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n const text = await response.text();\n \n // 需要YAML解析库,这里假设有yaml库\n // 如果没有,可以提示用户安装\n if (typeof (window as any).YAML !== 'undefined') {\n return (window as any).YAML.parse(text);\n }\n \n // 降级:尝试作为JSON解析(如果YAML格式简单)\n try {\n return JSON.parse(text);\n } catch {\n throw new Error('需要YAML解析库,请安装 yaml 包');\n }\n }\n\n // 在Node.js环境中,使用fs模块和yaml库\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const yaml = require('yaml');\n const content = fs.readFileSync(path, 'utf-8');\n return yaml.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载YAML配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从文件加载配置\n * \n * @param options - 加载选项\n * @returns 配置对象\n */\n static async loadFromFile(\n options: ConfigFileLoadOptions\n ): Promise<Partial<StartOptions>> {\n const {\n path,\n format = ConfigFileFormat.JSON,\n required = false,\n defaultConfig = {},\n } = options;\n\n if (!path) {\n if (required) {\n throw new Error('配置文件路径未指定');\n }\n return defaultConfig;\n }\n\n try {\n let config: Partial<StartOptions>;\n\n switch (format) {\n case ConfigFileFormat.JSON:\n config = await this.loadFromJSON(path);\n break;\n case ConfigFileFormat.YAML:\n config = await this.loadFromYAML(path);\n break;\n default:\n throw new Error(`不支持的配置文件格式: ${format}`);\n }\n\n logger.info(`成功加载配置文件: ${path}`);\n return config;\n } catch (error) {\n if (required) {\n throw error;\n }\n\n logger.warn(`配置文件加载失败,使用默认配置: ${path}`, error);\n return defaultConfig;\n }\n }\n\n /**\n * 合并配置(深度合并)\n * \n * @param base - 基础配置\n * @param override - 覆盖配置\n * @returns 合并后的配置\n */\n static mergeConfig(\n base: Partial<StartOptions>,\n override: Partial<StartOptions>\n ): Partial<StartOptions> {\n const merged = { ...base };\n\n for (const key in override) {\n if (!Object.prototype.hasOwnProperty.call(override, key)) {\n continue;\n }\n\n const baseValue = (merged as Record<string, unknown>)[key];\n const overrideValue = (override as Record<string, unknown>)[key];\n\n if (\n baseValue &&\n overrideValue &&\n typeof baseValue === 'object' &&\n typeof overrideValue === 'object' &&\n !Array.isArray(baseValue) &&\n !Array.isArray(overrideValue)\n ) {\n // 深度合并对象\n (merged as Record<string, unknown>)[key] = this.mergeConfig(\n baseValue as Partial<StartOptions>,\n overrideValue as Partial<StartOptions>\n );\n } else {\n // 直接覆盖\n (merged as Record<string, unknown>)[key] = overrideValue;\n }\n }\n\n return merged;\n }\n\n /**\n * 从多个源加载并合并配置\n * \n * @param sources - 配置源列表(按优先级从低到高)\n * @returns 合并后的配置\n */\n static async loadFromMultipleSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions>\n ): Promise<Partial<StartOptions>> {\n let merged: Partial<StartOptions> = {};\n\n for (const source of sources) {\n if ('path' in source && 'format' in source) {\n // 配置文件\n const fileConfig = await this.loadFromFile(source);\n merged = this.mergeConfig(merged, fileConfig);\n } else if (!('path' in source) && !('format' in source)) {\n // 配置对象\n merged = this.mergeConfig(merged, source as Partial<StartOptions>);\n }\n }\n\n return merged;\n }\n\n /**\n * 从环境变量加载配置\n * \n * 支持以下环境变量格式:\n * - FRAMEWORK_LOGGER_LEVEL=DEBUG\n * - FRAMEWORK_SHOW_SPLASH_SCREEN=always\n * - FRAMEWORK_MIN_SPLASH_SCREEN_TIME=1000\n * \n * @param prefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 配置对象\n */\n static loadFromEnv(prefix: string = 'FRAMEWORK_'): Partial<StartOptions> {\n const config: Partial<StartOptions> = {};\n\n if (typeof process === 'undefined' || !process.env) {\n return config;\n }\n\n // 遍历所有环境变量\n for (const [key, value] of Object.entries(process.env)) {\n if (!key.startsWith(prefix)) {\n continue;\n }\n\n // 移除前缀并转换为驼峰命名\n const configKey = key\n .slice(prefix.length)\n .toLowerCase()\n .split('_')\n .map((part, index) => \n index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)\n )\n .join('');\n\n // 尝试解析值\n let parsedValue: unknown = value;\n if (value === 'true' || value === 'false') {\n parsedValue = value === 'true';\n } else if (!isNaN(Number(value))) {\n parsedValue = Number(value);\n } else if (value?.startsWith('{') || value?.startsWith('[')) {\n try {\n parsedValue = JSON.parse(value);\n } catch {\n // 解析失败,使用原始值\n }\n }\n\n // 设置配置值\n (config as any)[configKey] = parsedValue;\n }\n\n logger.debug('从环境变量加载配置:', config);\n return config;\n }\n\n /**\n * 从多个源加载配置(包括环境变量)\n * \n * 优先级(从低到高):\n * 1. 默认配置\n * 2. 配置文件\n * 3. 环境变量\n * 4. 代码配置\n * \n * @param sources - 配置源列表\n * @param includeEnv - 是否包含环境变量,默认为 true\n * @param envPrefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 合并后的配置\n */\n static async loadFromAllSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions>,\n includeEnv: boolean = true,\n envPrefix: string = 'FRAMEWORK_'\n ): Promise<Partial<StartOptions>> {\n let merged: Partial<StartOptions> = {};\n\n // 1. 加载配置文件\n merged = await this.loadFromMultipleSources(sources);\n\n // 2. 加载环境变量(优先级高于配置文件)\n if (includeEnv) {\n const envConfig = this.loadFromEnv(envPrefix);\n merged = this.mergeConfig(merged, envConfig);\n }\n\n return merged;\n }\n}\n"],"names":["ConfigFileFormat","ConfigLoader","loadFromJSON","path","window","response","fetch","ok","Error","status","json","require","fs","content","readFileSync","JSON","parse","error","logger","loadFromYAML","text","YAML","yaml","loadFromFile","options","format","required","defaultConfig","config","info","warn","mergeConfig","base","override","merged","key","Object","prototype","hasOwnProperty","call","baseValue","overrideValue","Array","isArray","loadFromMultipleSources","sources","source","fileConfig","loadFromEnv","prefix","process","env","value","entries","startsWith","configKey","slice","length","toLowerCase","split","map","part","index","charAt","toUpperCase","join","parsedValue","isNaN","Number","debug","loadFromAllSources","includeEnv","envPrefix","envConfig"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/core/config/ConfigLoader.ts"],"sourcesContent":["/**\n * 配置文件加载模块\n * 支持从JSON/YAML文件加载配置\n * 优化:支持环境变量配置、配置热更新\n */\n\nimport { logger } from '../../utils';\nimport type { StartOptions } from '../types';\n\n/**\n * 配置文件格式\n */\nexport enum ConfigFileFormat {\n JSON = 'json',\n YAML = 'yaml',\n}\n\n/**\n * 配置文件加载选项\n */\nexport interface ConfigFileLoadOptions {\n /**\n * 配置文件路径\n */\n path?: string;\n\n /**\n * 配置文件格式\n */\n format?: ConfigFileFormat;\n\n /**\n * 是否必需(如果为false,文件不存在时不报错)\n */\n required?: boolean;\n\n /**\n * 默认配置(文件不存在时使用)\n */\n defaultConfig?: Partial<StartOptions>;\n}\n\n/**\n * 配置变更监听器\n */\nexport type ConfigChangeListener = (newConfig: Partial<StartOptions>, oldConfig: Partial<StartOptions>) => void;\n\n/**\n * 配置变更通知管理器\n */\nclass ConfigChangeNotifier {\n private listeners: Set<ConfigChangeListener> = new Set();\n\n /**\n * 添加配置变更监听器\n */\n addListener(listener: ConfigChangeListener): () => void {\n this.listeners.add(listener);\n // 返回取消监听的函数\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * 移除配置变更监听器\n */\n removeListener(listener: ConfigChangeListener): void {\n this.listeners.delete(listener);\n }\n\n /**\n * 通知配置变更\n */\n notify(newConfig: Partial<StartOptions>, oldConfig: Partial<StartOptions>): void {\n this.listeners.forEach((listener) => {\n try {\n listener(newConfig, oldConfig);\n } catch (error) {\n logger.warn('配置变更监听器执行失败:', error);\n }\n });\n }\n\n /**\n * 清除所有监听器\n */\n clear(): void {\n this.listeners.clear();\n }\n}\n\n/**\n * 全局配置变更通知器实例\n */\nconst configChangeNotifier = new ConfigChangeNotifier();\n\n/**\n * 配置加载器\n */\nexport class ConfigLoader {\n /**\n * 从JSON文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromJSON(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n return await response.json();\n }\n\n // 在Node.js环境中,使用fs模块\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const content = fs.readFileSync(path, 'utf-8');\n return JSON.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载JSON配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从YAML文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromYAML(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n const text = await response.text();\n \n // 需要YAML解析库,这里假设有yaml库\n // 如果没有,可以提示用户安装\n if (typeof (window as any).YAML !== 'undefined') {\n return (window as any).YAML.parse(text);\n }\n \n // 降级:尝试作为JSON解析(如果YAML格式简单)\n try {\n return JSON.parse(text);\n } catch {\n throw new Error('需要YAML解析库,请安装 yaml 包');\n }\n }\n\n // 在Node.js环境中,使用fs模块和yaml库\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const yaml = require('yaml');\n const content = fs.readFileSync(path, 'utf-8');\n return yaml.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载YAML配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从文件加载配置\n * \n * @param options - 加载选项\n * @returns 配置对象\n */\n static async loadFromFile(\n options: ConfigFileLoadOptions\n ): Promise<Partial<StartOptions>> {\n const {\n path,\n format = ConfigFileFormat.JSON,\n required = false,\n defaultConfig = {},\n } = options;\n\n if (!path) {\n if (required) {\n throw new Error('配置文件路径未指定');\n }\n return defaultConfig;\n }\n\n try {\n let config: Partial<StartOptions>;\n\n switch (format) {\n case ConfigFileFormat.JSON:\n config = await this.loadFromJSON(path);\n break;\n case ConfigFileFormat.YAML:\n config = await this.loadFromYAML(path);\n break;\n default:\n throw new Error(`不支持的配置文件格式: ${format}`);\n }\n\n logger.info(`成功加载配置文件: ${path}`);\n return config;\n } catch (error) {\n if (required) {\n throw error;\n }\n\n logger.warn(`配置文件加载失败,使用默认配置: ${path}`, error);\n return defaultConfig;\n }\n }\n\n /**\n * 合并配置(深度合并)\n * \n * @param base - 基础配置\n * @param override - 覆盖配置\n * @returns 合并后的配置\n */\n static mergeConfig(\n base: Partial<StartOptions>,\n override: Partial<StartOptions>\n ): Partial<StartOptions> {\n const merged = { ...base };\n\n for (const key in override) {\n if (!Object.prototype.hasOwnProperty.call(override, key)) {\n continue;\n }\n\n const baseValue = (merged as Record<string, unknown>)[key];\n const overrideValue = (override as Record<string, unknown>)[key];\n\n if (\n baseValue &&\n overrideValue &&\n typeof baseValue === 'object' &&\n typeof overrideValue === 'object' &&\n !Array.isArray(baseValue) &&\n !Array.isArray(overrideValue)\n ) {\n // 深度合并对象\n (merged as Record<string, unknown>)[key] = this.mergeConfig(\n baseValue as Partial<StartOptions>,\n overrideValue as Partial<StartOptions>\n );\n } else {\n // 直接覆盖\n (merged as Record<string, unknown>)[key] = overrideValue;\n }\n }\n\n return merged;\n }\n\n /**\n * 从多个源加载并合并配置\n * \n * @param sources - 配置源列表(按优先级从低到高)\n * @returns 合并后的配置\n */\n static async loadFromMultipleSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions>\n ): Promise<Partial<StartOptions>> {\n let merged: Partial<StartOptions> = {};\n\n for (const source of sources) {\n if ('path' in source && 'format' in source) {\n // 配置文件\n const fileConfig = await this.loadFromFile(source);\n merged = this.mergeConfig(merged, fileConfig);\n } else if (!('path' in source) && !('format' in source)) {\n // 配置对象\n merged = this.mergeConfig(merged, source as Partial<StartOptions>);\n }\n }\n\n return merged;\n }\n\n /**\n * 从环境变量加载配置\n * \n * 支持以下环境变量格式:\n * - FRAMEWORK_LOGGER_LEVEL=DEBUG\n * - FRAMEWORK_SHOW_SPLASH_SCREEN=always\n * - FRAMEWORK_MIN_SPLASH_SCREEN_TIME=1000\n * \n * @param prefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 配置对象\n */\n static loadFromEnv(prefix: string = 'FRAMEWORK_'): Partial<StartOptions> {\n const config: Partial<StartOptions> = {};\n\n if (typeof process === 'undefined' || !process.env) {\n return config;\n }\n\n // 遍历所有环境变量\n for (const [key, value] of Object.entries(process.env)) {\n if (!key.startsWith(prefix)) {\n continue;\n }\n\n // 移除前缀并转换为驼峰命名\n const configKey = key\n .slice(prefix.length)\n .toLowerCase()\n .split('_')\n .map((part, index) => \n index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)\n )\n .join('');\n\n // 尝试解析值\n let parsedValue: unknown = value;\n if (value === 'true' || value === 'false') {\n parsedValue = value === 'true';\n } else if (!isNaN(Number(value))) {\n parsedValue = Number(value);\n } else if (value?.startsWith('{') || value?.startsWith('[')) {\n try {\n parsedValue = JSON.parse(value);\n } catch {\n // 解析失败,使用原始值\n }\n }\n\n // 设置配置值\n (config as any)[configKey] = parsedValue;\n }\n\n logger.debug('从环境变量加载配置:', config);\n return config;\n }\n\n /**\n * 从多个源加载配置(包括环境变量)\n * \n * 优化:明确优先级,从低到高:\n * 1. 默认配置\n * 2. 配置文件\n * 3. 环境变量\n * 4. 代码配置(通过 sources 参数传入)\n * \n * @param sources - 配置源列表(代码配置,优先级最高)\n * @param defaultConfig - 默认配置(优先级最低)\n * @param includeEnv - 是否包含环境变量,默认为 true\n * @param envPrefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 合并后的配置\n */\n static async loadFromAllSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions> = [],\n defaultConfig: Partial<StartOptions> = {},\n includeEnv: boolean = true,\n envPrefix: string = 'FRAMEWORK_'\n ): Promise<Partial<StartOptions>> {\n // 保存旧配置用于变更通知\n const oldConfig: Partial<StartOptions> = { ...defaultConfig };\n\n // 1. 从默认配置开始\n let merged: Partial<StartOptions> = { ...defaultConfig };\n\n // 2. 加载配置文件(优先级高于默认配置)\n const fileConfigs = await this.loadFromMultipleSources(sources.filter(\n (source): source is ConfigFileLoadOptions => \n typeof source === 'object' && 'path' in source\n ));\n merged = this.mergeConfig(merged, fileConfigs);\n\n // 3. 加载环境变量(优先级高于配置文件)\n if (includeEnv) {\n const envConfig = this.loadFromEnv(envPrefix);\n merged = this.mergeConfig(merged, envConfig);\n }\n\n // 4. 合并代码配置(优先级最高)\n const codeConfigs = sources.filter(\n (source): source is Partial<StartOptions> => \n typeof source === 'object' && !('path' in source)\n );\n for (const codeConfig of codeConfigs) {\n merged = this.mergeConfig(merged, codeConfig);\n }\n\n // 通知配置变更\n configChangeNotifier.notify(merged, oldConfig);\n\n return merged;\n }\n\n /**\n * 添加配置变更监听器\n * \n * @param listener - 配置变更监听器\n * @returns 取消监听的函数\n */\n static onConfigChange(listener: ConfigChangeListener): () => void {\n return configChangeNotifier.addListener(listener);\n }\n\n /**\n * 移除配置变更监听器\n */\n static removeConfigChangeListener(listener: ConfigChangeListener): void {\n configChangeNotifier.removeListener(listener);\n }\n}\n"],"names":["ConfigFileFormat","ConfigLoader","ConfigChangeNotifier","addListener","listener","listeners","add","delete","removeListener","notify","newConfig","oldConfig","forEach","error","logger","warn","clear","Set","configChangeNotifier","loadFromJSON","path","window","response","fetch","ok","Error","status","json","require","fs","content","readFileSync","JSON","parse","loadFromYAML","text","YAML","yaml","loadFromFile","options","format","required","defaultConfig","config","info","mergeConfig","base","override","merged","key","Object","prototype","hasOwnProperty","call","baseValue","overrideValue","Array","isArray","loadFromMultipleSources","sources","source","fileConfig","loadFromEnv","prefix","process","env","value","entries","startsWith","configKey","slice","length","toLowerCase","split","map","part","index","charAt","toUpperCase","join","parsedValue","isNaN","Number","debug","loadFromAllSources","includeEnv","envPrefix","fileConfigs","filter","envConfig","codeConfigs","codeConfig","onConfigChange","removeConfigChangeListener"],"mappings":"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"}
@@ -32,6 +32,10 @@ export interface ConfigFileLoadOptions {
32
32
  */
33
33
  defaultConfig?: Partial<StartOptions>;
34
34
  }
35
+ /**
36
+ * 配置变更监听器
37
+ */
38
+ export type ConfigChangeListener = (newConfig: Partial<StartOptions>, oldConfig: Partial<StartOptions>) => void;
35
39
  /**
36
40
  * 配置加载器
37
41
  */
@@ -87,17 +91,29 @@ export declare class ConfigLoader {
87
91
  /**
88
92
  * 从多个源加载配置(包括环境变量)
89
93
  *
90
- * 优先级(从低到高):
94
+ * 优化:明确优先级,从低到高:
91
95
  * 1. 默认配置
92
96
  * 2. 配置文件
93
97
  * 3. 环境变量
94
- * 4. 代码配置
98
+ * 4. 代码配置(通过 sources 参数传入)
95
99
  *
96
- * @param sources - 配置源列表
100
+ * @param sources - 配置源列表(代码配置,优先级最高)
101
+ * @param defaultConfig - 默认配置(优先级最低)
97
102
  * @param includeEnv - 是否包含环境变量,默认为 true
98
103
  * @param envPrefix - 环境变量前缀,默认为 'FRAMEWORK_'
99
104
  * @returns 合并后的配置
100
105
  */
101
- static loadFromAllSources(sources: Array<Partial<StartOptions> | ConfigFileLoadOptions>, includeEnv?: boolean, envPrefix?: string): Promise<Partial<StartOptions>>;
106
+ static loadFromAllSources(sources?: Array<Partial<StartOptions> | ConfigFileLoadOptions>, defaultConfig?: Partial<StartOptions>, includeEnv?: boolean, envPrefix?: string): Promise<Partial<StartOptions>>;
107
+ /**
108
+ * 添加配置变更监听器
109
+ *
110
+ * @param listener - 配置变更监听器
111
+ * @returns 取消监听的函数
112
+ */
113
+ static onConfigChange(listener: ConfigChangeListener): () => void;
114
+ /**
115
+ * 移除配置变更监听器
116
+ */
117
+ static removeConfigChangeListener(listener: ConfigChangeListener): void;
102
118
  }
103
119
  //# sourceMappingURL=ConfigLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../../src/core/config/ConfigLoader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C;;GAEG;AACH,oBAAY,gBAAgB;IAC1B,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB;;;;;OAKG;WACU,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAyBvE;;;;;OAKG;WACU,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAuCvE;;;;;OAKG;WACU,YAAY,CACvB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAyCjC;;;;;;OAMG;IACH,MAAM,CAAC,WAAW,CAChB,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,EAC3B,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,OAAO,CAAC,YAAY,CAAC;IAiCxB;;;;;OAKG;WACU,uBAAuB,CAClC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,qBAAqB,CAAC,GAC5D,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAiBjC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,GAAE,MAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IA6CxE;;;;;;;;;;;;;OAaG;WACU,kBAAkB,CAC7B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,qBAAqB,CAAC,EAC7D,UAAU,GAAE,OAAc,EAC1B,SAAS,GAAE,MAAqB,GAC/B,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;CAclC"}
1
+ {"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../../src/core/config/ConfigLoader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C;;GAEG;AACH,oBAAY,gBAAgB;IAC1B,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;AAoDhH;;GAEG;AACH,qBAAa,YAAY;IACvB;;;;;OAKG;WACU,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAyBvE;;;;;OAKG;WACU,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAuCvE;;;;;OAKG;WACU,YAAY,CACvB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAyCjC;;;;;;OAMG;IACH,MAAM,CAAC,WAAW,CAChB,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,EAC3B,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,OAAO,CAAC,YAAY,CAAC;IAiCxB;;;;;OAKG;WACU,uBAAuB,CAClC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,qBAAqB,CAAC,GAC5D,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAiBjC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,GAAE,MAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IA6CxE;;;;;;;;;;;;;;OAcG;WACU,kBAAkB,CAC7B,OAAO,GAAE,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,qBAAqB,CAAM,EAClE,aAAa,GAAE,OAAO,CAAC,YAAY,CAAM,EACzC,UAAU,GAAE,OAAc,EAC1B,SAAS,GAAE,MAAqB,GAC/B,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAmCjC;;;;;OAKG;IACH,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAIjE;;OAEG;IACH,MAAM,CAAC,0BAA0B,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;CAGxE"}
@@ -1,3 +1,16 @@
1
+ function _define_property(obj, key, value) {
2
+ if (key in obj) {
3
+ Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ } else {
10
+ obj[key] = value;
11
+ }
12
+ return obj;
13
+ }
1
14
  /**
2
15
  * 配置文件加载模块
3
16
  * 支持从JSON/YAML文件加载配置
@@ -10,6 +23,46 @@
10
23
  ConfigFileFormat["YAML"] = "yaml";
11
24
  return ConfigFileFormat;
12
25
  }({});
26
+ /**
27
+ * 配置变更通知管理器
28
+ */ let ConfigChangeNotifier = class ConfigChangeNotifier {
29
+ /**
30
+ * 添加配置变更监听器
31
+ */ addListener(listener) {
32
+ this.listeners.add(listener);
33
+ // 返回取消监听的函数
34
+ return ()=>{
35
+ this.listeners.delete(listener);
36
+ };
37
+ }
38
+ /**
39
+ * 移除配置变更监听器
40
+ */ removeListener(listener) {
41
+ this.listeners.delete(listener);
42
+ }
43
+ /**
44
+ * 通知配置变更
45
+ */ notify(newConfig, oldConfig) {
46
+ this.listeners.forEach((listener)=>{
47
+ try {
48
+ listener(newConfig, oldConfig);
49
+ } catch (error) {
50
+ logger.warn('配置变更监听器执行失败:', error);
51
+ }
52
+ });
53
+ }
54
+ /**
55
+ * 清除所有监听器
56
+ */ clear() {
57
+ this.listeners.clear();
58
+ }
59
+ constructor(){
60
+ _define_property(this, "listeners", new Set());
61
+ }
62
+ };
63
+ /**
64
+ * 全局配置变更通知器实例
65
+ */ const configChangeNotifier = new ConfigChangeNotifier();
13
66
  /**
14
67
  * 配置加载器
15
68
  */ export class ConfigLoader {
@@ -203,27 +256,56 @@
203
256
  /**
204
257
  * 从多个源加载配置(包括环境变量)
205
258
  *
206
- * 优先级(从低到高):
259
+ * 优化:明确优先级,从低到高:
207
260
  * 1. 默认配置
208
261
  * 2. 配置文件
209
262
  * 3. 环境变量
210
- * 4. 代码配置
263
+ * 4. 代码配置(通过 sources 参数传入)
211
264
  *
212
- * @param sources - 配置源列表
265
+ * @param sources - 配置源列表(代码配置,优先级最高)
266
+ * @param defaultConfig - 默认配置(优先级最低)
213
267
  * @param includeEnv - 是否包含环境变量,默认为 true
214
268
  * @param envPrefix - 环境变量前缀,默认为 'FRAMEWORK_'
215
269
  * @returns 合并后的配置
216
- */ static async loadFromAllSources(sources, includeEnv = true, envPrefix = 'FRAMEWORK_') {
217
- let merged = {};
218
- // 1. 加载配置文件
219
- merged = await this.loadFromMultipleSources(sources);
220
- // 2. 加载环境变量(优先级高于配置文件)
270
+ */ static async loadFromAllSources(sources = [], defaultConfig = {}, includeEnv = true, envPrefix = 'FRAMEWORK_') {
271
+ // 保存旧配置用于变更通知
272
+ const oldConfig = {
273
+ ...defaultConfig
274
+ };
275
+ // 1. 从默认配置开始
276
+ let merged = {
277
+ ...defaultConfig
278
+ };
279
+ // 2. 加载配置文件(优先级高于默认配置)
280
+ const fileConfigs = await this.loadFromMultipleSources(sources.filter((source)=>typeof source === 'object' && 'path' in source));
281
+ merged = this.mergeConfig(merged, fileConfigs);
282
+ // 3. 加载环境变量(优先级高于配置文件)
221
283
  if (includeEnv) {
222
284
  const envConfig = this.loadFromEnv(envPrefix);
223
285
  merged = this.mergeConfig(merged, envConfig);
224
286
  }
287
+ // 4. 合并代码配置(优先级最高)
288
+ const codeConfigs = sources.filter((source)=>typeof source === 'object' && !('path' in source));
289
+ for (const codeConfig of codeConfigs){
290
+ merged = this.mergeConfig(merged, codeConfig);
291
+ }
292
+ // 通知配置变更
293
+ configChangeNotifier.notify(merged, oldConfig);
225
294
  return merged;
226
295
  }
296
+ /**
297
+ * 添加配置变更监听器
298
+ *
299
+ * @param listener - 配置变更监听器
300
+ * @returns 取消监听的函数
301
+ */ static onConfigChange(listener) {
302
+ return configChangeNotifier.addListener(listener);
303
+ }
304
+ /**
305
+ * 移除配置变更监听器
306
+ */ static removeConfigChangeListener(listener) {
307
+ configChangeNotifier.removeListener(listener);
308
+ }
227
309
  }
228
310
 
229
311
  //# sourceMappingURL=ConfigLoader.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/config/ConfigLoader.ts"],"sourcesContent":["/**\n * 配置文件加载模块\n * 支持从JSON/YAML文件加载配置\n * 优化:支持环境变量配置、配置热更新\n */\n\nimport { logger } from '../../utils';\nimport type { StartOptions } from '../types';\n\n/**\n * 配置文件格式\n */\nexport enum ConfigFileFormat {\n JSON = 'json',\n YAML = 'yaml',\n}\n\n/**\n * 配置文件加载选项\n */\nexport interface ConfigFileLoadOptions {\n /**\n * 配置文件路径\n */\n path?: string;\n\n /**\n * 配置文件格式\n */\n format?: ConfigFileFormat;\n\n /**\n * 是否必需(如果为false,文件不存在时不报错)\n */\n required?: boolean;\n\n /**\n * 默认配置(文件不存在时使用)\n */\n defaultConfig?: Partial<StartOptions>;\n}\n\n/**\n * 配置加载器\n */\nexport class ConfigLoader {\n /**\n * 从JSON文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromJSON(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n return await response.json();\n }\n\n // 在Node.js环境中,使用fs模块\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const content = fs.readFileSync(path, 'utf-8');\n return JSON.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载JSON配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从YAML文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromYAML(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n const text = await response.text();\n \n // 需要YAML解析库,这里假设有yaml库\n // 如果没有,可以提示用户安装\n if (typeof (window as any).YAML !== 'undefined') {\n return (window as any).YAML.parse(text);\n }\n \n // 降级:尝试作为JSON解析(如果YAML格式简单)\n try {\n return JSON.parse(text);\n } catch {\n throw new Error('需要YAML解析库,请安装 yaml 包');\n }\n }\n\n // 在Node.js环境中,使用fs模块和yaml库\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const yaml = require('yaml');\n const content = fs.readFileSync(path, 'utf-8');\n return yaml.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载YAML配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从文件加载配置\n * \n * @param options - 加载选项\n * @returns 配置对象\n */\n static async loadFromFile(\n options: ConfigFileLoadOptions\n ): Promise<Partial<StartOptions>> {\n const {\n path,\n format = ConfigFileFormat.JSON,\n required = false,\n defaultConfig = {},\n } = options;\n\n if (!path) {\n if (required) {\n throw new Error('配置文件路径未指定');\n }\n return defaultConfig;\n }\n\n try {\n let config: Partial<StartOptions>;\n\n switch (format) {\n case ConfigFileFormat.JSON:\n config = await this.loadFromJSON(path);\n break;\n case ConfigFileFormat.YAML:\n config = await this.loadFromYAML(path);\n break;\n default:\n throw new Error(`不支持的配置文件格式: ${format}`);\n }\n\n logger.info(`成功加载配置文件: ${path}`);\n return config;\n } catch (error) {\n if (required) {\n throw error;\n }\n\n logger.warn(`配置文件加载失败,使用默认配置: ${path}`, error);\n return defaultConfig;\n }\n }\n\n /**\n * 合并配置(深度合并)\n * \n * @param base - 基础配置\n * @param override - 覆盖配置\n * @returns 合并后的配置\n */\n static mergeConfig(\n base: Partial<StartOptions>,\n override: Partial<StartOptions>\n ): Partial<StartOptions> {\n const merged = { ...base };\n\n for (const key in override) {\n if (!Object.prototype.hasOwnProperty.call(override, key)) {\n continue;\n }\n\n const baseValue = (merged as Record<string, unknown>)[key];\n const overrideValue = (override as Record<string, unknown>)[key];\n\n if (\n baseValue &&\n overrideValue &&\n typeof baseValue === 'object' &&\n typeof overrideValue === 'object' &&\n !Array.isArray(baseValue) &&\n !Array.isArray(overrideValue)\n ) {\n // 深度合并对象\n (merged as Record<string, unknown>)[key] = this.mergeConfig(\n baseValue as Partial<StartOptions>,\n overrideValue as Partial<StartOptions>\n );\n } else {\n // 直接覆盖\n (merged as Record<string, unknown>)[key] = overrideValue;\n }\n }\n\n return merged;\n }\n\n /**\n * 从多个源加载并合并配置\n * \n * @param sources - 配置源列表(按优先级从低到高)\n * @returns 合并后的配置\n */\n static async loadFromMultipleSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions>\n ): Promise<Partial<StartOptions>> {\n let merged: Partial<StartOptions> = {};\n\n for (const source of sources) {\n if ('path' in source && 'format' in source) {\n // 配置文件\n const fileConfig = await this.loadFromFile(source);\n merged = this.mergeConfig(merged, fileConfig);\n } else if (!('path' in source) && !('format' in source)) {\n // 配置对象\n merged = this.mergeConfig(merged, source as Partial<StartOptions>);\n }\n }\n\n return merged;\n }\n\n /**\n * 从环境变量加载配置\n * \n * 支持以下环境变量格式:\n * - FRAMEWORK_LOGGER_LEVEL=DEBUG\n * - FRAMEWORK_SHOW_SPLASH_SCREEN=always\n * - FRAMEWORK_MIN_SPLASH_SCREEN_TIME=1000\n * \n * @param prefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 配置对象\n */\n static loadFromEnv(prefix: string = 'FRAMEWORK_'): Partial<StartOptions> {\n const config: Partial<StartOptions> = {};\n\n if (typeof process === 'undefined' || !process.env) {\n return config;\n }\n\n // 遍历所有环境变量\n for (const [key, value] of Object.entries(process.env)) {\n if (!key.startsWith(prefix)) {\n continue;\n }\n\n // 移除前缀并转换为驼峰命名\n const configKey = key\n .slice(prefix.length)\n .toLowerCase()\n .split('_')\n .map((part, index) => \n index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)\n )\n .join('');\n\n // 尝试解析值\n let parsedValue: unknown = value;\n if (value === 'true' || value === 'false') {\n parsedValue = value === 'true';\n } else if (!isNaN(Number(value))) {\n parsedValue = Number(value);\n } else if (value?.startsWith('{') || value?.startsWith('[')) {\n try {\n parsedValue = JSON.parse(value);\n } catch {\n // 解析失败,使用原始值\n }\n }\n\n // 设置配置值\n (config as any)[configKey] = parsedValue;\n }\n\n logger.debug('从环境变量加载配置:', config);\n return config;\n }\n\n /**\n * 从多个源加载配置(包括环境变量)\n * \n * 优先级(从低到高):\n * 1. 默认配置\n * 2. 配置文件\n * 3. 环境变量\n * 4. 代码配置\n * \n * @param sources - 配置源列表\n * @param includeEnv - 是否包含环境变量,默认为 true\n * @param envPrefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 合并后的配置\n */\n static async loadFromAllSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions>,\n includeEnv: boolean = true,\n envPrefix: string = 'FRAMEWORK_'\n ): Promise<Partial<StartOptions>> {\n let merged: Partial<StartOptions> = {};\n\n // 1. 加载配置文件\n merged = await this.loadFromMultipleSources(sources);\n\n // 2. 加载环境变量(优先级高于配置文件)\n if (includeEnv) {\n const envConfig = this.loadFromEnv(envPrefix);\n merged = this.mergeConfig(merged, envConfig);\n }\n\n return merged;\n }\n}\n"],"names":["logger","ConfigFileFormat","ConfigLoader","loadFromJSON","path","window","response","fetch","ok","Error","status","json","require","fs","content","readFileSync","JSON","parse","error","loadFromYAML","text","YAML","yaml","loadFromFile","options","format","required","defaultConfig","config","info","warn","mergeConfig","base","override","merged","key","Object","prototype","hasOwnProperty","call","baseValue","overrideValue","Array","isArray","loadFromMultipleSources","sources","source","fileConfig","loadFromEnv","prefix","process","env","value","entries","startsWith","configKey","slice","length","toLowerCase","split","map","part","index","charAt","toUpperCase","join","parsedValue","isNaN","Number","debug","loadFromAllSources","includeEnv","envPrefix","envConfig"],"mappings":"AAAA;;;;CAIC,GAED,SAASA,MAAM,QAAQ,cAAc;AAGrC;;CAEC,GACD,OAAO,IAAA,AAAKC,0CAAAA;;;WAAAA;MAGX;AA2BD;;CAEC,GACD,OAAO,MAAMC;IACX;;;;;GAKC,GACD,aAAaC,aAAaC,IAAY,EAAkC;QACtE,IAAI;YACF,qBAAqB;YACrB,IAAI,OAAOC,WAAW,aAAa;gBACjC,MAAMC,WAAW,MAAMC,MAAMH;gBAC7B,IAAI,CAACE,SAASE,EAAE,EAAE;oBAChB,MAAM,IAAIC,MAAM,CAAC,UAAU,EAAEL,KAAK,EAAE,EAAEE,SAASI,MAAM,CAAC,CAAC,CAAC;gBAC1D;gBACA,OAAO,MAAMJ,SAASK,IAAI;YAC5B;YAEA,qBAAqB;YACrB,IAAI,OAAOC,YAAY,aAAa;gBAClC,MAAMC,KAAKD,QAAQ;gBACnB,MAAME,UAAUD,GAAGE,YAAY,CAACX,MAAM;gBACtC,OAAOY,KAAKC,KAAK,CAACH;YACpB;YAEA,MAAM,IAAIL,MAAM;QAClB,EAAE,OAAOS,OAAO;YACdlB,OAAOkB,KAAK,CAAC,CAAC,cAAc,EAAEd,MAAM,EAAEc;YACtC,MAAMA;QACR;IACF;IAEA;;;;;GAKC,GACD,aAAaC,aAAaf,IAAY,EAAkC;QACtE,IAAI;YACF,qBAAqB;YACrB,IAAI,OAAOC,WAAW,aAAa;gBACjC,MAAMC,WAAW,MAAMC,MAAMH;gBAC7B,IAAI,CAACE,SAASE,EAAE,EAAE;oBAChB,MAAM,IAAIC,MAAM,CAAC,UAAU,EAAEL,KAAK,EAAE,EAAEE,SAASI,MAAM,CAAC,CAAC,CAAC;gBAC1D;gBACA,MAAMU,OAAO,MAAMd,SAASc,IAAI;gBAEhC,uBAAuB;gBACvB,gBAAgB;gBAChB,IAAI,OAAO,AAACf,OAAegB,IAAI,KAAK,aAAa;oBAC/C,OAAO,AAAChB,OAAegB,IAAI,CAACJ,KAAK,CAACG;gBACpC;gBAEA,4BAA4B;gBAC5B,IAAI;oBACF,OAAOJ,KAAKC,KAAK,CAACG;gBACpB,EAAE,OAAM;oBACN,MAAM,IAAIX,MAAM;gBAClB;YACF;YAEA,2BAA2B;YAC3B,IAAI,OAAOG,YAAY,aAAa;gBAClC,MAAMC,KAAKD,QAAQ;gBACnB,MAAMU,OAAOV,QAAQ;gBACrB,MAAME,UAAUD,GAAGE,YAAY,CAACX,MAAM;gBACtC,OAAOkB,KAAKL,KAAK,CAACH;YACpB;YAEA,MAAM,IAAIL,MAAM;QAClB,EAAE,OAAOS,OAAO;YACdlB,OAAOkB,KAAK,CAAC,CAAC,cAAc,EAAEd,MAAM,EAAEc;YACtC,MAAMA;QACR;IACF;IAEA;;;;;GAKC,GACD,aAAaK,aACXC,OAA8B,EACE;QAChC,MAAM,EACJpB,IAAI,EACJqB,eAA8B,EAC9BC,WAAW,KAAK,EAChBC,gBAAgB,CAAC,CAAC,EACnB,GAAGH;QAEJ,IAAI,CAACpB,MAAM;YACT,IAAIsB,UAAU;gBACZ,MAAM,IAAIjB,MAAM;YAClB;YACA,OAAOkB;QACT;QAEA,IAAI;YACF,IAAIC;YAEJ,OAAQH;gBACN;oBACEG,SAAS,MAAM,IAAI,CAACzB,YAAY,CAACC;oBACjC;gBACF;oBACEwB,SAAS,MAAM,IAAI,CAACT,YAAY,CAACf;oBACjC;gBACF;oBACE,MAAM,IAAIK,MAAM,CAAC,YAAY,EAAEgB,QAAQ;YAC3C;YAEAzB,OAAO6B,IAAI,CAAC,CAAC,UAAU,EAAEzB,MAAM;YAC/B,OAAOwB;QACT,EAAE,OAAOV,OAAO;YACd,IAAIQ,UAAU;gBACZ,MAAMR;YACR;YAEAlB,OAAO8B,IAAI,CAAC,CAAC,iBAAiB,EAAE1B,MAAM,EAAEc;YACxC,OAAOS;QACT;IACF;IAEA;;;;;;GAMC,GACD,OAAOI,YACLC,IAA2B,EAC3BC,QAA+B,EACR;QACvB,MAAMC,SAAS;YAAE,GAAGF,IAAI;QAAC;QAEzB,IAAK,MAAMG,OAAOF,SAAU;YAC1B,IAAI,CAACG,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACN,UAAUE,MAAM;gBACxD;YACF;YAEA,MAAMK,YAAY,AAACN,MAAkC,CAACC,IAAI;YAC1D,MAAMM,gBAAgB,AAACR,QAAoC,CAACE,IAAI;YAEhE,IACEK,aACAC,iBACA,OAAOD,cAAc,YACrB,OAAOC,kBAAkB,YACzB,CAACC,MAAMC,OAAO,CAACH,cACf,CAACE,MAAMC,OAAO,CAACF,gBACf;gBACA,SAAS;gBACRP,MAAkC,CAACC,IAAI,GAAG,IAAI,CAACJ,WAAW,CACzDS,WACAC;YAEJ,OAAO;gBACL,OAAO;gBACNP,MAAkC,CAACC,IAAI,GAAGM;YAC7C;QACF;QAEA,OAAOP;IACT;IAEA;;;;;GAKC,GACD,aAAaU,wBACXC,OAA6D,EAC7B;QAChC,IAAIX,SAAgC,CAAC;QAErC,KAAK,MAAMY,UAAUD,QAAS;YAC5B,IAAI,UAAUC,UAAU,YAAYA,QAAQ;gBAC1C,OAAO;gBACP,MAAMC,aAAa,MAAM,IAAI,CAACxB,YAAY,CAACuB;gBAC3CZ,SAAS,IAAI,CAACH,WAAW,CAACG,QAAQa;YACpC,OAAO,IAAI,CAAE,CAAA,UAAUD,MAAK,KAAM,CAAE,CAAA,YAAYA,MAAK,GAAI;gBACvD,OAAO;gBACPZ,SAAS,IAAI,CAACH,WAAW,CAACG,QAAQY;YACpC;QACF;QAEA,OAAOZ;IACT;IAEA;;;;;;;;;;GAUC,GACD,OAAOc,YAAYC,SAAiB,YAAY,EAAyB;QACvE,MAAMrB,SAAgC,CAAC;QAEvC,IAAI,OAAOsB,YAAY,eAAe,CAACA,QAAQC,GAAG,EAAE;YAClD,OAAOvB;QACT;QAEA,WAAW;QACX,KAAK,MAAM,CAACO,KAAKiB,MAAM,IAAIhB,OAAOiB,OAAO,CAACH,QAAQC,GAAG,EAAG;YACtD,IAAI,CAAChB,IAAImB,UAAU,CAACL,SAAS;gBAC3B;YACF;YAEA,eAAe;YACf,MAAMM,YAAYpB,IACfqB,KAAK,CAACP,OAAOQ,MAAM,EACnBC,WAAW,GACXC,KAAK,CAAC,KACNC,GAAG,CAAC,CAACC,MAAMC,QACVA,UAAU,IAAID,OAAOA,KAAKE,MAAM,CAAC,GAAGC,WAAW,KAAKH,KAAKL,KAAK,CAAC,IAEhES,IAAI,CAAC;YAER,QAAQ;YACR,IAAIC,cAAuBd;YAC3B,IAAIA,UAAU,UAAUA,UAAU,SAAS;gBACzCc,cAAcd,UAAU;YAC1B,OAAO,IAAI,CAACe,MAAMC,OAAOhB,SAAS;gBAChCc,cAAcE,OAAOhB;YACvB,OAAO,IAAIA,OAAOE,WAAW,QAAQF,OAAOE,WAAW,MAAM;gBAC3D,IAAI;oBACFY,cAAclD,KAAKC,KAAK,CAACmC;gBAC3B,EAAE,OAAM;gBACN,aAAa;gBACf;YACF;YAEA,QAAQ;YACPxB,MAAc,CAAC2B,UAAU,GAAGW;QAC/B;QAEAlE,OAAOqE,KAAK,CAAC,cAAczC;QAC3B,OAAOA;IACT;IAEA;;;;;;;;;;;;;GAaC,GACD,aAAa0C,mBACXzB,OAA6D,EAC7D0B,aAAsB,IAAI,EAC1BC,YAAoB,YAAY,EACA;QAChC,IAAItC,SAAgC,CAAC;QAErC,YAAY;QACZA,SAAS,MAAM,IAAI,CAACU,uBAAuB,CAACC;QAE5C,uBAAuB;QACvB,IAAI0B,YAAY;YACd,MAAME,YAAY,IAAI,CAACzB,WAAW,CAACwB;YACnCtC,SAAS,IAAI,CAACH,WAAW,CAACG,QAAQuC;QACpC;QAEA,OAAOvC;IACT;AACF"}
1
+ {"version":3,"sources":["../../../src/core/config/ConfigLoader.ts"],"sourcesContent":["/**\n * 配置文件加载模块\n * 支持从JSON/YAML文件加载配置\n * 优化:支持环境变量配置、配置热更新\n */\n\nimport { logger } from '../../utils';\nimport type { StartOptions } from '../types';\n\n/**\n * 配置文件格式\n */\nexport enum ConfigFileFormat {\n JSON = 'json',\n YAML = 'yaml',\n}\n\n/**\n * 配置文件加载选项\n */\nexport interface ConfigFileLoadOptions {\n /**\n * 配置文件路径\n */\n path?: string;\n\n /**\n * 配置文件格式\n */\n format?: ConfigFileFormat;\n\n /**\n * 是否必需(如果为false,文件不存在时不报错)\n */\n required?: boolean;\n\n /**\n * 默认配置(文件不存在时使用)\n */\n defaultConfig?: Partial<StartOptions>;\n}\n\n/**\n * 配置变更监听器\n */\nexport type ConfigChangeListener = (newConfig: Partial<StartOptions>, oldConfig: Partial<StartOptions>) => void;\n\n/**\n * 配置变更通知管理器\n */\nclass ConfigChangeNotifier {\n private listeners: Set<ConfigChangeListener> = new Set();\n\n /**\n * 添加配置变更监听器\n */\n addListener(listener: ConfigChangeListener): () => void {\n this.listeners.add(listener);\n // 返回取消监听的函数\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * 移除配置变更监听器\n */\n removeListener(listener: ConfigChangeListener): void {\n this.listeners.delete(listener);\n }\n\n /**\n * 通知配置变更\n */\n notify(newConfig: Partial<StartOptions>, oldConfig: Partial<StartOptions>): void {\n this.listeners.forEach((listener) => {\n try {\n listener(newConfig, oldConfig);\n } catch (error) {\n logger.warn('配置变更监听器执行失败:', error);\n }\n });\n }\n\n /**\n * 清除所有监听器\n */\n clear(): void {\n this.listeners.clear();\n }\n}\n\n/**\n * 全局配置变更通知器实例\n */\nconst configChangeNotifier = new ConfigChangeNotifier();\n\n/**\n * 配置加载器\n */\nexport class ConfigLoader {\n /**\n * 从JSON文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromJSON(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n return await response.json();\n }\n\n // 在Node.js环境中,使用fs模块\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const content = fs.readFileSync(path, 'utf-8');\n return JSON.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载JSON配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从YAML文件加载配置\n * \n * @param path - 文件路径\n * @returns 配置对象\n */\n static async loadFromYAML(path: string): Promise<Partial<StartOptions>> {\n try {\n // 在浏览器环境中,需要通过网络请求加载\n if (typeof window !== 'undefined') {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`无法加载配置文件: ${path} (${response.status})`);\n }\n const text = await response.text();\n \n // 需要YAML解析库,这里假设有yaml库\n // 如果没有,可以提示用户安装\n if (typeof (window as any).YAML !== 'undefined') {\n return (window as any).YAML.parse(text);\n }\n \n // 降级:尝试作为JSON解析(如果YAML格式简单)\n try {\n return JSON.parse(text);\n } catch {\n throw new Error('需要YAML解析库,请安装 yaml 包');\n }\n }\n\n // 在Node.js环境中,使用fs模块和yaml库\n if (typeof require !== 'undefined') {\n const fs = require('fs');\n const yaml = require('yaml');\n const content = fs.readFileSync(path, 'utf-8');\n return yaml.parse(content);\n }\n\n throw new Error('不支持的环境:无法加载配置文件');\n } catch (error) {\n logger.error(`加载YAML配置文件失败: ${path}`, error);\n throw error;\n }\n }\n\n /**\n * 从文件加载配置\n * \n * @param options - 加载选项\n * @returns 配置对象\n */\n static async loadFromFile(\n options: ConfigFileLoadOptions\n ): Promise<Partial<StartOptions>> {\n const {\n path,\n format = ConfigFileFormat.JSON,\n required = false,\n defaultConfig = {},\n } = options;\n\n if (!path) {\n if (required) {\n throw new Error('配置文件路径未指定');\n }\n return defaultConfig;\n }\n\n try {\n let config: Partial<StartOptions>;\n\n switch (format) {\n case ConfigFileFormat.JSON:\n config = await this.loadFromJSON(path);\n break;\n case ConfigFileFormat.YAML:\n config = await this.loadFromYAML(path);\n break;\n default:\n throw new Error(`不支持的配置文件格式: ${format}`);\n }\n\n logger.info(`成功加载配置文件: ${path}`);\n return config;\n } catch (error) {\n if (required) {\n throw error;\n }\n\n logger.warn(`配置文件加载失败,使用默认配置: ${path}`, error);\n return defaultConfig;\n }\n }\n\n /**\n * 合并配置(深度合并)\n * \n * @param base - 基础配置\n * @param override - 覆盖配置\n * @returns 合并后的配置\n */\n static mergeConfig(\n base: Partial<StartOptions>,\n override: Partial<StartOptions>\n ): Partial<StartOptions> {\n const merged = { ...base };\n\n for (const key in override) {\n if (!Object.prototype.hasOwnProperty.call(override, key)) {\n continue;\n }\n\n const baseValue = (merged as Record<string, unknown>)[key];\n const overrideValue = (override as Record<string, unknown>)[key];\n\n if (\n baseValue &&\n overrideValue &&\n typeof baseValue === 'object' &&\n typeof overrideValue === 'object' &&\n !Array.isArray(baseValue) &&\n !Array.isArray(overrideValue)\n ) {\n // 深度合并对象\n (merged as Record<string, unknown>)[key] = this.mergeConfig(\n baseValue as Partial<StartOptions>,\n overrideValue as Partial<StartOptions>\n );\n } else {\n // 直接覆盖\n (merged as Record<string, unknown>)[key] = overrideValue;\n }\n }\n\n return merged;\n }\n\n /**\n * 从多个源加载并合并配置\n * \n * @param sources - 配置源列表(按优先级从低到高)\n * @returns 合并后的配置\n */\n static async loadFromMultipleSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions>\n ): Promise<Partial<StartOptions>> {\n let merged: Partial<StartOptions> = {};\n\n for (const source of sources) {\n if ('path' in source && 'format' in source) {\n // 配置文件\n const fileConfig = await this.loadFromFile(source);\n merged = this.mergeConfig(merged, fileConfig);\n } else if (!('path' in source) && !('format' in source)) {\n // 配置对象\n merged = this.mergeConfig(merged, source as Partial<StartOptions>);\n }\n }\n\n return merged;\n }\n\n /**\n * 从环境变量加载配置\n * \n * 支持以下环境变量格式:\n * - FRAMEWORK_LOGGER_LEVEL=DEBUG\n * - FRAMEWORK_SHOW_SPLASH_SCREEN=always\n * - FRAMEWORK_MIN_SPLASH_SCREEN_TIME=1000\n * \n * @param prefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 配置对象\n */\n static loadFromEnv(prefix: string = 'FRAMEWORK_'): Partial<StartOptions> {\n const config: Partial<StartOptions> = {};\n\n if (typeof process === 'undefined' || !process.env) {\n return config;\n }\n\n // 遍历所有环境变量\n for (const [key, value] of Object.entries(process.env)) {\n if (!key.startsWith(prefix)) {\n continue;\n }\n\n // 移除前缀并转换为驼峰命名\n const configKey = key\n .slice(prefix.length)\n .toLowerCase()\n .split('_')\n .map((part, index) => \n index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)\n )\n .join('');\n\n // 尝试解析值\n let parsedValue: unknown = value;\n if (value === 'true' || value === 'false') {\n parsedValue = value === 'true';\n } else if (!isNaN(Number(value))) {\n parsedValue = Number(value);\n } else if (value?.startsWith('{') || value?.startsWith('[')) {\n try {\n parsedValue = JSON.parse(value);\n } catch {\n // 解析失败,使用原始值\n }\n }\n\n // 设置配置值\n (config as any)[configKey] = parsedValue;\n }\n\n logger.debug('从环境变量加载配置:', config);\n return config;\n }\n\n /**\n * 从多个源加载配置(包括环境变量)\n * \n * 优化:明确优先级,从低到高:\n * 1. 默认配置\n * 2. 配置文件\n * 3. 环境变量\n * 4. 代码配置(通过 sources 参数传入)\n * \n * @param sources - 配置源列表(代码配置,优先级最高)\n * @param defaultConfig - 默认配置(优先级最低)\n * @param includeEnv - 是否包含环境变量,默认为 true\n * @param envPrefix - 环境变量前缀,默认为 'FRAMEWORK_'\n * @returns 合并后的配置\n */\n static async loadFromAllSources(\n sources: Array<Partial<StartOptions> | ConfigFileLoadOptions> = [],\n defaultConfig: Partial<StartOptions> = {},\n includeEnv: boolean = true,\n envPrefix: string = 'FRAMEWORK_'\n ): Promise<Partial<StartOptions>> {\n // 保存旧配置用于变更通知\n const oldConfig: Partial<StartOptions> = { ...defaultConfig };\n\n // 1. 从默认配置开始\n let merged: Partial<StartOptions> = { ...defaultConfig };\n\n // 2. 加载配置文件(优先级高于默认配置)\n const fileConfigs = await this.loadFromMultipleSources(sources.filter(\n (source): source is ConfigFileLoadOptions => \n typeof source === 'object' && 'path' in source\n ));\n merged = this.mergeConfig(merged, fileConfigs);\n\n // 3. 加载环境变量(优先级高于配置文件)\n if (includeEnv) {\n const envConfig = this.loadFromEnv(envPrefix);\n merged = this.mergeConfig(merged, envConfig);\n }\n\n // 4. 合并代码配置(优先级最高)\n const codeConfigs = sources.filter(\n (source): source is Partial<StartOptions> => \n typeof source === 'object' && !('path' in source)\n );\n for (const codeConfig of codeConfigs) {\n merged = this.mergeConfig(merged, codeConfig);\n }\n\n // 通知配置变更\n configChangeNotifier.notify(merged, oldConfig);\n\n return merged;\n }\n\n /**\n * 添加配置变更监听器\n * \n * @param listener - 配置变更监听器\n * @returns 取消监听的函数\n */\n static onConfigChange(listener: ConfigChangeListener): () => void {\n return configChangeNotifier.addListener(listener);\n }\n\n /**\n * 移除配置变更监听器\n */\n static removeConfigChangeListener(listener: ConfigChangeListener): void {\n configChangeNotifier.removeListener(listener);\n }\n}\n"],"names":["logger","ConfigFileFormat","ConfigChangeNotifier","addListener","listener","listeners","add","delete","removeListener","notify","newConfig","oldConfig","forEach","error","warn","clear","Set","configChangeNotifier","ConfigLoader","loadFromJSON","path","window","response","fetch","ok","Error","status","json","require","fs","content","readFileSync","JSON","parse","loadFromYAML","text","YAML","yaml","loadFromFile","options","format","required","defaultConfig","config","info","mergeConfig","base","override","merged","key","Object","prototype","hasOwnProperty","call","baseValue","overrideValue","Array","isArray","loadFromMultipleSources","sources","source","fileConfig","loadFromEnv","prefix","process","env","value","entries","startsWith","configKey","slice","length","toLowerCase","split","map","part","index","charAt","toUpperCase","join","parsedValue","isNaN","Number","debug","loadFromAllSources","includeEnv","envPrefix","fileConfigs","filter","envConfig","codeConfigs","codeConfig","onConfigChange","removeConfigChangeListener"],"mappings":"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"}
@@ -26,6 +26,7 @@ const _antd = require("antd");
26
26
  const _utils = require("../../utils");
27
27
  const _errors = require("../../utils/errors");
28
28
  const _initialization = require("../initialization");
29
+ const _ErrorHandler = require("./ErrorHandler");
29
30
  function _getRequireWildcardCache(nodeInterop) {
30
31
  if (typeof WeakMap !== "function") return null;
31
32
  var cacheBabelInterop = new WeakMap();
@@ -70,30 +71,43 @@ function _interop_require_wildcard(obj, nodeInterop) {
70
71
  function ErrorBoundary({ children, fallback, onError, showInConsole = true, resetKeys, onReset, onResetKeysChange }) {
71
72
  // 使用 ref 存储重试计数,在多次错误之间保持状态
72
73
  const retryCountRef = (0, _react.useRef)(0);
74
+ // 优化:使用统一的错误处理器
75
+ const errorHandler = (0, _react.useMemo)(()=>(0, _ErrorHandler.getDefaultErrorHandler)(), []);
73
76
  // 处理错误,将标准 Error 转换为 FrameworkError
74
- const handleError = (error, errorInfo)=>{
77
+ const handleError = (0, _react.useCallback)(async (error, errorInfo)=>{
75
78
  const normalizedError = _errors.errorUtils.normalizeError(error);
76
79
  // 将 react-error-boundary 的 errorInfo 转换为 React 的 ErrorInfo 格式
77
80
  const reactErrorInfo = {
78
81
  componentStack: errorInfo.componentStack || ''
79
82
  };
80
- // 记录错误
81
- _utils.logger.error('错误边界捕获到错误:', {
82
- error: normalizedError.toJSON(),
83
- errorInfo: {
84
- componentStack: reactErrorInfo.componentStack
85
- }
83
+ // 使用统一的错误处理器处理错误
84
+ const handleResult = await errorHandler.handleError(normalizedError, {
85
+ componentStack: reactErrorInfo.componentStack,
86
+ source: 'ErrorBoundary'
86
87
  });
88
+ // 如果错误处理器没有处理错误,使用默认处理
89
+ if (!handleResult.handled) {
90
+ _utils.logger.error('错误边界捕获到错误:', {
91
+ error: normalizedError.toJSON(),
92
+ errorInfo: {
93
+ componentStack: reactErrorInfo.componentStack
94
+ }
95
+ });
96
+ }
87
97
  // 调用错误回调
88
98
  if (onError) {
89
99
  onError(normalizedError, reactErrorInfo);
90
100
  }
91
- // 在控制台显示错误
101
+ // 在控制台显示错误(如果配置了)
92
102
  if (showInConsole) {
93
103
  console.error('错误边界捕获到错误:', normalizedError);
94
104
  console.error('错误信息:', reactErrorInfo);
95
105
  }
96
- };
106
+ }, [
107
+ errorHandler,
108
+ onError,
109
+ showInConsole
110
+ ]);
97
111
  // 处理重置
98
112
  const handleReset = ()=>{
99
113
  // 清除初始化错误状态