⚙️:"孔子"
生产级配置加载器,具有宇宙相距级能力和干净的原始API
重点
- QQ 定义配置分辨率, 包含 4 个搜索策略( 无、 项目、 工作空间、 全球) 和 40+ 每个模块名的默认搜索位置
- QQ 对10+格式的一等支持——JSON,YAML,TOML,JSON5,JSONC,.env,JS/TS模块,和packet.json属性——兼有Aync和同步加载器
- 配置( 导入/ 扩展) 、 环境覆盖( env/ $ 开发) 、 计划验证 、 插件钩子 —— 全部内置, 零配置
- * 带有完整的DI容器的清洁建筑内部,使每个部件都能够测试、替换和独立延伸
目录
说明
孔蒂格是个 已键入可扩展配置加载器 用于解决跨项目、工作空间和全球范围的配置文件的Node.js——有决定性的搜索计划、配置继承链、环境覆盖、计划验证和插件生命周期钩.
与 清洁建筑 由依赖性注射容器提供动力的Configer提供了宇宙图的灵活性,具有更强的型号安全性、明确的出错代码和模块化的内部设计.
实际世界使用案例
- CLI 工具与开发工具: 自动发现
.toolrc, (中文(简体) ),.toolrc.yaml, (中文(简体) ),tool.config.ts,或package.json属性——和ESLint,Prettier,和Babel一样——但有完整的TypeScript通用和出框的图案验证. - Monorepo 配置: 使用
workspace搜索策略从任何嵌入式软件包到工作空间根,将共享的基础配置与每个软件包的覆盖合并. - 多环境应用程序: 定义
$development, (中文(简体) ),$production,或$env在配置文件中直接设置。 Configer 剥去不活动的环境,并会使活动的环境被深层地淹没——不需要额外的工具. - 插件生态系统: 以
beforeFind, (中文(简体) ),afterRead,以及onError用钩子来注入默认值,对照外部的计数法进行验证,或者进行日志诊断. - 图书馆作者: 装运打字合同(
IConfigOptions<TEntity>)所以消费者可以获得自动完成和编译时间安全,用于您的工具配置.
QQ 技术堆栈
| 类别 | 技术 |
|---|---|
| 语言 | 类型脚本 |
| 运行时间 | 节点.js >= 20.0.0 |
| 构建工具 | 滚动, 类型脚本编译器 |
| 测试 | V8病毒,覆盖范围 |
| 线性 | ESLint, 高级 |
| 软件包管理器 | 无 |
| 排雷中心/发改委 | 语义释放、Husky、Contlint |
| 依赖关系 | (原始内容存档于2013-10-12). yaml, smol-toml, json5, jsonc-parser, dotenv, @elsikora/cladi |
* 特性
- ✨ **同步客户端( S) —— 说
createConfiger()用手表支持的合成IO;createConfigerSync()具有严格故障快速保证的同步唯一流动** - ✨ **10+内置装载器 JSON、JSON5、JSONC、YAML、TOML、env、JS(.js/.cjs/.mjs)、TypeScript(.ts/.cts/.mts)和包裹.json财产提取**
- ✨ **4 搜索策略 —— 说
none(当前目录),project(直到包裹.json),workspace(最多为单雷波根),global(包括XDG配置之家)** - ✨ ** 继承 合并父配置通过
extends或者说$import循环参考检测和源链跟踪指令** - ✨ ** 环境重叠 —— 说
$development, (中文(简体) ),$production,或$env地图块为活动环境而深处并剥离输出** - ✨ ** 建于Schema验证 – 宣告所需的字段,类型,默认值,嵌入对象,数组项目,以及没有外部依赖性的自定义验证器**
- ✨ **活期钩 —— 说
beforeFind, (中文(简体) ),afterFind, (中文(简体) ),beforeRead, (中文(简体) ),afterRead,以及onError用于扩展配置分辨率每个阶段的钩子** - ✨ ** 海关装载器 登记任何文件扩展名的同步/同步加载器(
.ini, (中文(简体) ),.xml, (中文(简体) ),.custom通过loaders备选案文** - ✨ **观察模式 ——文件系统监视器,有已解开的刷新,自动缓存无效,并清空
IWatchHandle.close()清理** - ✨ ** 捕捉层 ——有颗粒的单独查找/读取缓存
clearFindCache(), (中文(简体) ),clearReadCache(),以及clearCaches()控制器** - ✨ ** 稳定出错代码 - 每一次失败都可能
ConfigError有机器可读CODE和人可读SUGGESTIONS阵列** - ✨ ** 清洁建筑 - 域驱动地层(域-应用-基础设施-演示),配有可测试性的全设计资料容器**
建筑
系统架构
flowchart TD
presentation[Presentation Layer]
application[Application Layer]
domain[Domain Layer]
infrastructure[Infrastructure Layer]
presentation --> application
presentation --> infrastructure
application --> domain
infrastructure --> application
infrastructure --> domain
subgraph presentation
createConfiger[createConfiger]
createConfigerSync[createConfigerSync]
end
subgraph infrastructure
diContainer[DI Container]
loaderRegistry[Loader Registry]
searchResolvers[Search Resolvers]
cacheAdapter[Memory Cache]
schemaValidator[Schema Validator]
deepMerge[Deep Merge]
fileWatcher[File Watcher]
end
subgraph application
resolveSearchPlan[ResolveSearchPlanUseCase]
end
subgraph domain
configClient[IConfigClient]
configResult[IConfigResult]
configError[ConfigError]
pluginContract[IConfigPlugin]
end
数据流动
sequenceDiagram
participant User
participant Client as ConfigClient
participant Plugins as Plugin Hooks
participant SearchPlan as ResolveSearchPlan
participant Cache as MemoryCache
participant Loader as LoaderRegistry
participant Merge as DeepMerge
participant Schema as SchemaValidator
User->>Client: findConfig(searchFrom?)
Client->>Plugins: beforeFind(context)
Client->>Cache: getFindResult(key)
alt Cache Hit
Cache-->>Client: cached result
else Cache Miss
Client->>SearchPlan: execute(options)
SearchPlan-->>Client: candidateFilepaths[]
loop Each candidate
Client->>Loader: load(filepath, content)
Loader-->>Client: raw config
Client->>Merge: resolveInheritance(extends/$import)
Merge-->>Client: merged config
Client->>Client: resolveEnvironmentOverrides($env)
Client->>Schema: validate(config, descriptor)
Schema-->>Client: validated config
end
Client->>Cache: setFindResult(key, result)
end
Client->>Plugins: afterFind(result, context)
Client-->>User: IConfigResult or null
项目结构
单击以扩展
Configer/
├── docs/
│ ├── api-reference/
│ │ ├── error-codes/
│ │ ├── factories/
│ │ ├── interfaces/
│ │ ├── types/
│ │ ├── _meta.js
│ │ └── page.mdx
│ ├── core-concepts/
│ │ ├── caching-and-watch/
│ │ ├── environment-overrides/
│ │ ├── inheritance-and-merge/
│ │ ├── resolution-flow/
│ │ ├── schema-validation/
│ │ ├── _meta.js
│ │ └── page.mdx
│ ├── getting-started/
│ │ ├── first-client/
│ │ ├── first-config-read/
│ │ ├── installation/
│ │ ├── sync-mode/
│ │ ├── _meta.js
│ │ └── page.mdx
│ ├── guides/
│ │ ├── custom-loaders/
│ │ ├── custom-search-places/
│ │ ├── package-json-property/
│ │ ├── plugins/
│ │ ├── watch-mode/
│ │ ├── _meta.js
│ │ └── page.mdx
│ ├── _meta.js
│ └── page.mdx
├── examples/
│ ├── 01-basic-usage/
│ │ └── main.ts
│ ├── 02-search-strategies/
│ │ └── main.ts
│ ├── 03-file-formats/
│ │ └── main.ts
│ ├── 04-inheritance/
│ │ └── main.ts
│ ├── 05-environment-overrides/
│ │ └── main.ts
│ ├── 06-plugins/
│ │ └── main.ts
│ ├── 07-schema-validation/
│ │ └── main.ts
│ ├── 08-custom-loaders/
│ │ └── main.ts
│ ├── 09-watch-mode/
│ │ └── main.ts
│ ├── 10-package-json-property/
│ │ └── main.ts
│ ├── README.md
│ └── tsconfig.json
├── scripts/
│ ├── clean.function.js
│ └── validate-documentation.function.js
├── src/
│ ├── application/
│ │ ├── dto/
│ │ ├── interface/
│ │ ├── use-case/
│ │ └── index.ts
│ ├── domain/
│ │ ├── entity/
│ │ ├── error/
│ │ ├── type/
│ │ └── index.ts
│ ├── infrastructure/
│ │ ├── adapter/
│ │ ├── cache/
│ │ ├── di/
│ │ ├── loader/
│ │ ├── resolver/
│ │ ├── service/
│ │ ├── watcher/
│ │ └── index.ts
│ ├── presentation/
│ │ ├── function/
│ │ └── index.ts
│ └── index.ts
├── test/
│ ├── e2e/
│ │ ├── configer-error-paths.end-to-end.test.ts
│ │ └── configer-integration.end-to-end.test.ts
│ └── unit/
│ ├── application/
│ ├── domain/
│ ├── infrastructure/
│ └── presentation/
├── commitlint.config.js
├── eslint.config.js
├── generated-logo.png
├── lint-staged.config.js
├── package-lock.json
├── package.json
├── prettier.config.js
├── README.md
├── release.config.js
├── rollup.config.js
├── tsconfig.build.json
├── tsconfig.json
├── vitest.config.js
├── vitest.end-to-end.config.js
└── vitest.unit.config.js
· 先决条件
- 节点.js >= 20.0.0
- npm >= 9.0.0 (或 pnpm / 纱线等同)
- 与无害环境管理兼容的项目("类型":包件中的"模块". json)
* 安装
# Using npm
npm install @elsikora/configer
# Using pnpm
pnpm add @elsikora/configer
# Using yarn
yarn add @elsikora/configer
Verify the installation:
ts
import { createConfiger } from '@elsikora/configer';
const client = createConfiger({ moduleName: 'my-app' });
console.log(typeof client.findConfig === 'function'); // true
使用量
基本合成用法
import { createConfiger } from '@elsikora/configer';
import type { IConfigClient, IConfigResult } from '@elsikora/configer';
type AppConfig = {
serviceName: string;
isFeatureEnabled: boolean;
};
const client: IConfigClient<AppConfig> = createConfiger<AppConfig>({
moduleName: 'my-app',
cwd: process.cwd(),
});
const result: IConfigResult<AppConfig> | null = await client.findConfig();
if (result) {
console.log(result.filepath); // /project/.my-apprc.json
console.log(result.config?.serviceName); // "billing-api"
}
同步模式
import { createConfigerSync } from '@elsikora/configer';
const client = createConfigerSync<{ retries: number }>({
moduleName: 'my-app',
});
const result = client.findConfig();
console.log(result?.config?.retries); // 3
搜索策略
// Search only the current directory
const client = createConfiger({ moduleName: 'app', searchStrategy: 'none' });
// Ascend until nearest package.json
const client = createConfiger({ moduleName: 'app', searchStrategy: 'project' });
// Ascend until workspace root (.git, pnpm-workspace.yaml, etc.)
const client = createConfiger({ moduleName: 'app', searchStrategy: 'workspace' });
// Traverse project + workspace + global config directory
const client = createConfiger({ moduleName: 'app', searchStrategy: 'global' });
配置继承
创建基础配置( C)base.config.json:
{ "logLevel": "info", "retries": 1 }
在您的应用配置中扩展( T).my-apprc.json:
{
"extends": "./base.config.json",
"retries": 3
}
结果 : { logLevel: "info", retries: 3 } 与 sources 追踪整个链条.
环境覆盖
{
"apiUrl": "https://api.default.com",
"$development": { "apiUrl": "https://dev.api.com" },
"$env": {
"production": { "apiUrl": "https://prod.api.com" }
}
}
const client = createConfiger({
moduleName: 'app',
envName: 'development', // or reads NODE_ENV automatically
});
Schema 验证
import type { ISchemaDescriptor } from '@elsikora/configer';
const schema: ISchemaDescriptor<{ serviceName: string; retryCount: number }> = {
type: 'object',
properties: {
serviceName: { type: 'string', isRequired: true },
retryCount: { type: 'number', defaultValue: 3 },
},
shouldAllowUnknownProperties: false,
};
const client = createConfiger({
moduleName: 'app',
schema,
});
插件钩
const client = createConfiger({
moduleName: 'app',
plugins: [
{
name: 'source-marker',
afterRead: (result) => ({
...result,
config: { ...result.config, _loadedFrom: result.filepath },
}),
onError: (error) => console.error('Config error:', error.message),
},
],
});
自定义装入器
const client = createConfiger({
moduleName: 'app',
searchPlaces: ['config.ini'],
shouldMergeSearchPlaces: false,
loaders: {
'.ini': {
asyncLoader: (_filepath, content) => parseIni(content),
syncLoader: (_filepath, content) => parseIni(content),
},
},
});
监视模式
const handle = client.watchConfig((error, result) => {
if (error) return console.error(error);
console.log('Config changed:', result?.config);
});
// Cleanup on shutdown
process.on('SIGTERM', () => handle.close());
从软件包读取。 json
const client = createConfiger({
moduleName: 'my-tool',
packageProperty: 'config.myTool', // or ['config', 'myTool']
searchPlaces: ['package.json'],
shouldMergeSearchPlaces: false,
});
* 路线图
单击以扩展
| 任务/ 特性 | 状态 |
|---|---|
| 有搜索策略的核心 async/ sync 配置客户端 | 完毕 |
| JSON、YAML、TOML、JSON5、JSONC、env、JS/TS的装货机 | 完毕 |
通过 extends 财务报告和审定财务报表 $import 有循环检测 | 完毕 |
环境覆盖( E)$env, (中文(简体) ), $development, (中文(简体) ), $production(中文(简体) ) | 完毕 |
| 用嵌入式对象和阵列进行内置的系统验证 | 完毕 |
| 插件生命周期钩( 在查找前, 读取后, 在 Error 上) | 完毕 |
| 以已解除的文件系统监视监视模式 | 完毕 |
| 带有完整 DI 容器的清洁建筑 | 完毕 |
| 综合单元和e2e测试套房 | 完毕 |
| 带有指南和 API 参考的 MDX 文档站点 | 完毕 |
| 远程配置源支持( HTTP/ S3) | 执行中 |
| 配置加密/解密插件 | 执行中 |
| JSON Schema / Zod 用于计划验证的适配器 | 执行中 |
| 配置 diff 和 迁移工具 | 执行中 |
问 题
单击以扩展
孔菲格跟宇宙飞有什么区别?
Configer由宇宙取出灵感,但从零开始用TypeScript通用,Clean Architecture 内部取出,以及附加的功能: Config 继承,环境上覆盖, schema 验证,插件钩,和表模式——都内置而无外包.
我能从宇宙飞移吗?
- 替换
cosmiconfig(moduleName, options)→createConfiger({ moduleName, ...options }) - 替换
search()→findConfig() - 替换
load(filepath)→readConfig(filepath) - 使用
createConfigerSync用于同步 API - 将自定义转换为插件( S)
beforeRead, (中文(简体) ),afterRead, (中文(简体) ),onError(中文(简体) )
框外支持什么文件格式 ?
JSON、JSON5、JSONC、YAML(.yaml/.yml)、TOML、.env、JavaScript模块(.js/.cjs/.mjs)、TypeScript模块(.ts/.cts/.mts),以及 package.json 与巢穴地产取出.
我能在普通JS项目中使用这个吗?
Configer仅作为无害环境管理发布。 你的项目需要 "type": "module" 在软件包中 import() 从CJS代码.
我何时应该使用同步客户端 vs async客户端?
使用 createConfigerSync() 只有当您的运行时间严格要求同步行为(如同步CLI启动)时. 同步客户端无法装入 .mjs, (中文(简体) ), .mts,或 .ts 文件,插件钩子不能返回承诺。 对于所有其他案件,宁可 createConfiger() (同声.
搜索策略如何运作?
- 无: 只搜索起始目录
- 项目: 在找到目录之前将目录发送到
package.json - 工作空间: 向工作空间根标记( Ascends )
.git, (中文(简体) ),pnpm-workspace.yaml, (中文(简体) ),turbo.json页:1 - 全球: 将项目/工作空间与
$XDG_CONFIG_HOME/<moduleName>或者说~/.config/<moduleName>
我怎么处理错误?
所有错误都是 ConfigError 拥有稳定 .CODE 用于程序处理的不动产和 .SUGGESTIONS 包含可操作的固定建议。 使用 error.CODE 用于分支逻辑和 error.message 用于显示用户的输出.
许可证
这个项目的许可证根据 麻省理工学院。 。 。 .
承认
- 灵感来自 宇宙图 ——节点.js生态系统中配置文件发现的黄金标准
- 与 @elsikora/cladi:我无法想象 轻量级依赖性注射容器
- 解析电源 雅姆尔, (中文(简体) ), 闪闪发光, (中文(简体) ), 纪事5, (中文(简体) ), jsonc- parser (日语),以及 多腾v
- 测试 维特 财务报告和审定财务报表 @elsikora/cladi测试
- 感谢开源社群的反馈和启发