首页
/ airi 仓库 pnpm 配置指南:用 Config Dependencies 跨仓库共享 Hooks、Catalogs、Overrides 与补丁

airi 仓库 pnpm 配置指南:用 Config Dependencies 跨仓库共享 Hooks、Catalogs、Overrides 与补丁

2026-09-05 20:48:54作者:滑思眉Philip

本篇技术指南围绕 pnpm 的 Config Dependencies(配置依赖)展开:它是让多个仓库复用同一套 pnpm 钩子、设置、catalog 版本表、补丁与 overrides 的机制。读完本文,你将掌握 configDependencies 的声明方式、约束规则、自动加载插件的命名约定,以及如何借助 updateConfig 钩子把 catalog 与设置"推送"到消费方——并以 airi 这个大型 pnpm 单仓库中的真实配置(catalogpatchedDependenciesoverridesallowBuilds 等)作为落地参照,理解这类中心化配置在超大型工作区中的实际形态。

什么是 Config Dependencies

Config dependencies 是一批 npm 包,pnpm 会在安装所有常规依赖之前先行安装它们,使它们有机会向当前项目提供钩子(hooks)、设置(settings)、补丁(patches)、catalogs 和 overrides。核心意图是:你只需维护一个共享的 "pnpm 配置包",就能在所有仓库中消费它,避免把同一套 pnpmfile 钩子逻辑、同一份版本目录、同一组补丁文件复制到每个仓库。

声明 Config Dependencies

声明位置是工作区根目录的 pnpm-workspace.yaml 中的 configDependencies 字段;它们的完整性(integrity)会记录在 pnpm-lock.yaml 内的一个专属 env-lockfile 文档中,与常规依赖的 lockfile 部分隔离。

configDependencies:
  my-configs: "1.0.0"

--config 标志添加(pnpm 会把它写入 configDependencies 而不是普通的 dependencies):

pnpm add --config my-configs
pnpm add --config @myorg/pnpm-plugin-my-catalogs

需要注意的前提:pnpm 的绝大多数设置现统一放在 pnpm-workspace.yaml(camelCase 键),.npmrc 仅用于认证/registry 凭据,package.json 中的 pnpm 字段已不再被读取。airi 仓库锁定的包管理器版本为 pnpm@11.24.0(见 package.jsonpackageManager 字段),Config Dependencies 即在该版本线(pnpm 10.x/11.x)下可用。

约束:Config Dependencies 能声明什么、不能声明什么

这是使用 Config Dependencies 前必须牢记的三条硬性限制:

  • 不允许普通 dependencies。可以声明 optionalDependencies,但只能有一层深度(one level deep)。
  • 不允许生命周期脚本preinstallpostinstall 等)。这既限制了攻击面,也保证了"配置包只做配置"的纯度。
  • optionalDependencies 必须使用精确版本(exact versions)。由于常用于平台相关二进制(esbuild 风格的条件安装),版本范围或 dist-tag 会被拒绝,以确保安装结果可复现。

自动加载插件:命名约定触发 pnpmfile 自动装载

一个满足以下任一命名模式的 config dependency:

  • pnpm-plugin-*
  • @*/pnpm-plugin-*
  • @pnpm/plugin-*

其包根目录下的 pnpmfile.mjs(或 .cjs)会被 pnpm 自动加载,无需在消费方仓库中手工引入。这意味着"插件即配置":发布一个 @myorg/pnpm-plugin-my-catalogs,任何仓库只要 pnpm add --config 它,就会自动获得其中定义的钩子。

用例一:从共享包导入钩子逻辑

由于 config deps 先于 .pnpmfile.mjs 加载完成,工作区根目录的 pnpmfile 可以直接 import 它们的导出:

import { readPackage } from '.pnpm-config/my-hooks'

export const hooks = { readPackage }

readPackage 钩子在解析前可以修改依赖的 package.json(补 peer 依赖、固定传递版本、替换已弃用依赖等)。共享包 .pnpm-config/my-hooks 承载这段逻辑,多个仓库各自维护的 .pnpmfile.mjs 只需一行 import,逻辑升级集中在配置包发版,而不是逐仓库改代码。

用例二:用 updateConfig 共享设置与 Catalogs

updateConfig 钩子在安装前修改 pnpm 自身配置,是 config dependency 里威力最大的钩子。一个 catalog 插件可以这样向消费方注入版本目录:

export const hooks = {
  updateConfig(config) {
    config.catalogs.default ??= {}
    config.catalogs.default['is-odd'] = '1.0.0'
    return config
  }
}

安装为 config dependency 后,消费方即可像本地定义 catalog 一样使用它:

pnpm add is-odd@catalog:   # 实际安装 is-odd@1.0.0,package.json 写入 "is-odd": "catalog:"

这里与 features-catalogs.md 的机制衔接:catalog:catalog:default 的简写,catalog: 协议可用于 dependencies/devDependencies/peerDependencies/optionalDependencies 以及 pnpm-workspace.yamloverrides 中。airi 的 pnpm-workspace.yaml 正是 catalog 体系的典型重度使用场景——它维护了 400 余条 catalog: 版本表(从 @vitest/*xsai 的命名 catalog)、catalogMode: prefer 模式、overrides(如 axios: npm:feaxios@^0.0.23)、packageExtensions 与供应链相关的 allowBuildsminimumReleaseAge: 4320 等设置。从源码结构看,这正是 Config Dependencies 设计要解决的问题的反面教材:当一个团队维护多个结构相似的仓库时,把这些数百行配置逐仓复制并手工同步,极易漂移;而 updateConfig + configDependencies 把"版本的唯一事实来源"收敛到一个可发版的 npm 包里。

用例三:共享补丁文件

补丁文件可以存放在 config dependency 内部,patchedDependencies 通过 node_modules/.pnpm-config/ 下的相对路径引用:

configDependencies:
  my-patches: "1.0.0"
patchedDependencies:
  react: "node_modules/.pnpm-config/my-patches/react.patch"

对照 airi 仓库的本地补丁用法可以看到两者形态一致、只是存放位置不同:pnpm-workspace.yaml 中的 patchedDependenciesuiohook-napi@1.5.5 映射到 patches/uiohook-napi@1.5.5.patch,同样的写法还有 mineflayer-pathfinderpixi-live2d-displaysponsorkit@17.1.0 等。若这类"通用修复补丁"需要在组织内多个仓库生效,把它们收进一个 my-patches 配置包、各仓库 configDependencies 一行引用,就是文档给出的中心化方案;补丁的创建与格式细节可参考 features-patches.md 中的 pnpm patch / pnpm patch-commit 流程。

关键要点

  • 在一个包里集中管理 hooks、settings、catalogs、overrides 与 patches,被多个仓库消费。
  • 通过 pnpm-workspace.yamlconfigDependencies 声明;它们先于常规依赖安装,integrity 记录在 lockfile 内的专属 env-lockfile 文档中。
  • 约束:无普通 dependencies、无生命周期脚本;optionalDependencies 必须精确版本,保证安装可复现。
  • pnpm-plugin-* / @*/pnpm-plugin-* / @pnpm/plugin-* 命名的包自动加载其 pnpmfile.mjs/.cjs
  • updateConfig 钩子搭配,把设置与 catalog 注入消费方项目;与 .pnpmfile.mjs 的 import 能力搭配,把 readPackage 等钩子逻辑外置到共享包。

与 airi 仓库现状的关系

需要说明:在当前 airi 仓库中检索不到 configDependencies 声明——它目前是单仓库内的自包含配置,共享逻辑(catalog、overrides、补丁、packageExtensionsallowBuilds)都集中在根目录的 pnpm-workspace.yaml 中,由 pnpm-lock.yamlcatalogs 段落锁定 specifier 与解析后的实际版本。上述 Config Dependencies 方案适用于 airi 团队若要把这套配置复用到组织内其他 pnpm 仓库的场景:把 pnpm-workspace.yaml 中可参数化的部分(catalog 版本表、补丁文件、readPackage 钩子)抽成 @moeru/*@proj-airi/* scope 下的配置包发布,各仓库一行 pnpm add --config 即可同步。pnpmfile 各钩子的完整参考见 features-hooks.md,工作区与过滤机制见 core-workspaces.md

登录后查看全文
热门项目推荐
相关项目推荐