Logo of c12

c12

智能配置加载器。

c12(发音为 /siːtwelv/,类似于 c-twelve)是一个智能配置加载器。

✅ 特性

  • .js, .ts, .mjs, .cjs, .mts, .cts .json 配置文件加载器,基于 unjs/jiti
  • .jsonc, .json5, .yaml, .yml, .toml 配置文件加载器,基于 unjs/confbox
  • .config/ 目录支持,遵循 config dir 提案
  • .rc 配置支持,基于 unjs/rc9
  • .env 文件支持,基于 dotenv
  • 多个源通过 unjs/defu 合并
  • 从最近的 package.json 文件读取配置
  • 从多个本地或 Git 源扩展配置
  • 使用环境特定配置覆盖
  • 配置监视器,支持自动重载和 HMR

🦴 被以下项目使用

用法

安装包

# ✨ Auto-detect
npx nypm install c12

# npm
npm install c12

# yarn
yarn add c12

# pnpm
pnpm install c12

# bun
bun install c12

导入

ESM (Node.js, Bun)

import { loadConfig, watchConfig } from "c12";

CommonJS (传统 Node.js)

const { loadConfig, watchConfig } = require("c12");

加载配置

// Get loaded config
const { config } = await loadConfig({});

// Get resolved config and extended layers
const { config, configFile, layers } = await loadConfig({});

加载优先级

c12 使用 unjs/defu 按以下顺序合并配置源

  1. 通过选项传入的配置覆盖
  2. 当前工作目录(CWD)中的配置文件
  3. 当前工作目录(CWD)中的 RC 文件
  4. 用户主目录中的全局 RC 文件
  5. 来自 package.json 的配置
  6. 通过选项传入的默认配置
  7. 扩展的配置层

选项

cwd

从此工作目录解析配置。默认值为 process.cwd()

name

配置基础名称。默认值为 config

configFile

不带扩展名的配置文件名。默认值由 name 生成(例如,如果 namefoo,则配置文件将是 => foo.config)。

设置为 false 以避免加载配置文件。

rcFile

RC 配置文件名。默认值由 name 生成 (name=foo => .foorc)。

设置为 false 以禁用加载 RC 配置。

globalRC

从工作区目录和用户主目录加载 RC 配置。仅在提供 rcFile 时启用。设置为 false 以禁用此功能。

dotenv

如果启用,则加载 .env 文件。默认禁用。

packageJson

从最近的 package.json 文件加载配置。默认禁用。

如果传入 true,c12 将使用 package.json 中的 name 字段。

您也可以传入字符串或字符串数组作为值来使用这些字段。

defaults

指定默认配置。它具有最低优先级,并且在配置扩展后应用。

defaultConfig

指定默认配置。它在配置扩展前应用。

overrides

指定覆盖配置。它具有最高优先级,并且在配置扩展前应用。

omit$Keys

排除已解析配置中以 $ 开头的环境特定和内置键。默认值为 false

jiti

用于导入配置文件的自定义 unjs/jiti 实例。

jitiOptions

用于导入配置文件的自定义 unjs/jiti 选项。

giget

从 Git 源扩展层时,传递给 unjs/giget 的选项。

envName

用于环境特定配置的环境名称。

默认值为 process.env.NODE_ENV。您可以将 envName 设置为 false 或空字符串以禁用此功能。

扩展配置

如果解析的配置包含 extends 键,它将用于扩展配置。

扩展可以是嵌套的,每个层可以从一个或多个基础扩展。

最终配置是使用 unjs/defu 合并扩展选项和用户选项的结果。

extends 中的每个项都是一个字符串,可以是当前配置文件的绝对或相对路径,指向用于扩展的配置文件或包含配置文件的目录。如果它以 github:gitlab:bitbucket:https: 开头,c12 会自动克隆它。

对于自定义合并策略,您可以通过 layers 属性直接访问每个层。

示例

// config.ts
export default {
  colors: {
    primary: "user_primary",
  },
  extends: ["./theme"],
};
// config.dev.ts
export default {
  dev: true,
};
// theme/config.ts
export default {
  extends: "../base",
  colors: {
    primary: "theme_primary",
    secondary: "theme_secondary",
  },
};
// base/config.ts
export default {
  colors: {
    primary: 'base_primary'
    text: 'base_text'
  }
}

加载的配置将如下所示

{
  dev: true,
  colors: {
    primary: 'user_primary',
    secondary: 'theme_secondary',
    text: 'base_text'
  }
}

[
 { config: /* theme config */, configFile: /* path/to/theme/config.ts */, cwd: /* path/to/theme */ },
 { config: /* base  config */, configFile: /* path/to/base/config.ts  */, cwd: /* path/to/base */ },
 { config: /* dev   config */, configFile: /* path/to/config.dev.ts  */, cwd: /* path/ */ },
]

从远程源扩展配置层

您还可以从 npm 或 GitHub 等远程源扩展配置。

在仓库中,应该有一个 config.ts (或 config.{name}.ts)文件才能被视为有效的配置层。

示例: 从 GitHub 仓库扩展

// config.ts
export default {
  extends: "gh:user/repo",
};

示例: 从带有分支和子路径的 GitHub 仓库扩展

// config.ts
export default {
  extends: "gh:user/repo/theme#dev",
};

示例: 扩展私有仓库并安装依赖项

// config.ts
export default {
  extends: ["gh:user/repo", { auth: process.env.GITHUB_TOKEN, install: true }],
};

您可以在层配置中向 giget: {} 传递更多选项。

更多信息请参考 unjs/giget

环境特定配置

用户可以使用以下配置键定义环境特定配置

  • $test: {...}
  • $development: {...}
  • $production: {...}
  • $env: { [env]: {...} }

c12 尝试匹配 envName,如果指定,则覆盖环境配置。

注意: 环境将在扩展每个配置层时应用。这样,层可以提供环境特定配置。

示例

{
  // Default configuration
  logLevel: 'info',

  // Environment overrides
  $test: { logLevel: 'silent' },
  $development: { logLevel: 'warning' },
  $production: { logLevel: 'error' },
  $env: {
    staging: { logLevel: 'debug' }
  }
}

监视配置

您可以使用 watchConfig 而不是 loadConfig 来加载配置并监视所有预期配置路径中的更改、添加和删除,并自动使用新配置重新加载。

生命周期钩子

  • onWatch: 此函数总是在配置更新、添加或删除时(尝试重新加载配置之前)调用。
  • acceptHMR: 通过实现此函数,您可以比较旧函数和新函数,并在不需要完全重新加载时返回 true
  • onUpdate: 此函数总是在新配置更新后调用。如果 acceptHMR 返回 true,则会跳过此函数。
import { watchConfig } from "c12";

const config = watchConfig({
  cwd: ".",
  // chokidarOptions: {}, // Default is { ignoreInitial: true }
  // debounce: 200 // Default is 100. You can set it to false to disable debounced watcher
  onWatch: (event) => {
    console.log("[watcher]", event.type, event.path);
  },
  acceptHMR({ oldConfig, newConfig, getDiff }) {
    const diff = getDiff();
    if (diff.length === 0) {
      console.log("No config changed detected!");
      return true; // No changes!
    }
  },
  onUpdate({ oldConfig, newConfig, getDiff }) {
    const diff = getDiff();
    console.log("Config updated:\n" + diff.map((i) => i.toJSON()).join("\n"));
  },
});

console.log("watching config files:", config.watchingFiles);
console.log("initial config", config.config);

// Stop watcher when not needed anymore
// await config.unwatch();

贡献

本地开发
  • 克隆此仓库
  • 安装最新 LTS 版本的 Node.js
  • 使用 corepack enable 启用 Corepack
  • 使用 pnpm install 安装依赖项
  • 使用 pnpm devpnpm test 运行测试

许可

根据 MIT 许可发布。由 @pi0社区 💛 制作