pnpm-workspace.yaml 是 pnpm 管理 Monorepo(单体仓库)的核心配置文件。它定义了哪些目录属于当前工作区,并提供了许多强大的全局依赖管理策略。

以下是一份生产环境级别的详细配置说明及完整模板。

📖 核心配置项详解

1. packages (必选)

定义哪些目录属于 pnpm workspace。支持 glob 模式

  • *:匹配当前目录下的一级子目录。
  • **:匹配任意深度的子目录。
  • !:排除特定目录。

2. catalog (pnpm v9+ 强烈推荐)

依赖目录。用于在 Monorepo 中统一管理依赖版本,解决“版本碎片化”问题。

  • default:默认目录。
  • 也可以自定义多个目录(如 react18, react19),方便平滑升级。

3. allowBuilds (安全白名单)

当全局设置了 ignore-scripts=true 时,此列表中的包被允许执行 preinstall / postinstall 脚本。

4. ignoredBuiltDependencies (构建黑名单)

无论全局设置如何,强制跳过这些包的安装/构建脚本。常用于那些构建极慢、容易报错,且你确信不需要其构建步骤的包。

5. peerDependencyRules (对等依赖规则)

用于消除烦人的 peer dependency 警告,或强制解决版本冲突。

  • ignoreMissing:忽略缺失的 peer 依赖警告。
  • allowedVersions:放宽对 peer 依赖的版本要求。

📝 完整配置模板 (可直接复制使用)

# =========================================================
# pnpm-workspace.yaml
# =========================================================

# 1. 定义工作区包含的目录 (必填)
packages:
  # 包含 apps 目录下所有一级子目录 (如 apps/web, apps/admin)
  - 'apps/*'
  # 包含 packages 目录下所有一级子目录 (如 packages/ui, packages/utils)
  - 'packages/*'
  # 包含 components 目录下的任意深度子目录
  - 'components/**'
  # 排除特定的测试目录或废弃目录
  - '!packages/deprecated-*'
  - '!**/test/**'

# 2. 依赖目录 (Catalogs) - pnpm v9+ 特性
catalog:
  # 默认目录,子项目可通过 "catalog:" 引用
  react: ^18.2.0
  react-dom: ^18.2.0
  typescript: ^5.3.0
  vite: ^5.0.0
  # 自定义目录:例如为某个旧项目保留的 react 17 版本
  # react17:
  #   react: ^17.0.2
  #   react-dom: ^17.0.2

# 3. 构建脚本控制 (安全与性能)
# 允许以下包执行 postinstall 等脚本 (通常是需要下载二进制文件或编译 C++ 的包)
allowBuilds:
  - 'esbuild'
  - 'esbuild-*'
  - '@swc/core'
  - 'sharp'
  - 'prisma'
  - '@prisma/client'

# 强制忽略以下包的构建脚本 (即使它们请求执行)
ignoredBuiltDependencies:
  - 'core-js' # 经常弹出赞助提示,可忽略
  - 'vue-demi' # 某些情况下不需要其 postinstall

# 4. 依赖解析规则 (解决警告与冲突)
peerDependencyRules:
  # 忽略特定包的 peer 依赖缺失警告
  ignoreMissing:
    - 'react'
    - 'react-dom'
    - '@babel/core'
  
  # 允许特定包使用更宽泛的 peer 依赖版本 (解决 "wanted x but got y" 警告)
  allowedVersions:
    # 允许所有包将 react 的 peer 依赖视为满足 ^18.0.0
    react: ^18.0.0
    # 针对特定包放宽限制
    'eslint-plugin-react':
      eslint: ^8.0.0

# 5. 全局依赖覆盖 (Overrides)
# 强制整个 workspace 使用特定版本的依赖,常用于修复安全漏洞或统一底层库
overrides:
  # 强制所有子项目使用安全的 lodash 版本
  lodash: ^4.17.21
  # 强制使用特定版本的 node-fetch (修复 CVE)
  node-fetch: ^2.6.7
  # 覆盖某个包内部的子依赖
  'some-package>unsafe-dep': ^1.0.0

🔗 如何在 package.json 中使用这些配置?

配置好 pnpm-workspace.yaml 后,子项目中的 package.json 会变得极其简洁:

场景 A:使用 Catalog (pnpm v9+)

{
  "name": "@my-org/web-app",
  "dependencies": {
    "react": "catalog:", 
    "react-dom": "catalog:",
    "typescript": "catalog:"
  }
}

注:catalog: 告诉 pnpm:“去 pnpm-workspace.yamlcatalog 里找这个包的版本”。

场景 B:使用自定义 Catalog

{
  "name": "@my-org/legacy-app",
  "dependencies": {
    "react": "catalog:react17",
    "react-dom": "catalog:react17"
  }
}

场景 C:引用 Workspace 内的本地包

{
  "name": "@my-org/web-app",
  "dependencies": {
    "@my-org/ui": "workspace:*",
    "@my-org/utils": "workspace:^1.0.0"
  }
}

注:workspace:\* 表示始终链接本地最新版本;workspace:^1.0.0 表示链接本地版本,但发布时会转换为正常的 semver 范围。

⚠️ 常见坑点与注意事项

  1. pnpm-workspace.yaml 必须放在项目根目录:与根目录的 package.json 同级。

  2. .npmrc 的关系

    • pnpm-workspace.yaml 专注于 Workspace 结构、Catalog 和 pnpm 专属的高级依赖规则
    • 一些通用的 npm 配置(如 registryshamefully-hoist、全局的 ignore-scripts)仍然建议放在根目录的 .npmrc 文件中。两者互补,不冲突。
  3. 修改配置后需重新安装:如果你修改了 packages 路径或 catalog 版本,务必删除 node_modulespnpm-lock.yaml,然后重新运行 pnpm install,否则可能会出现幽灵依赖或版本未更新的问题。

  4. Glob 语法的陷阱packages/* 只匹配 packages 下的一级目录。如果你的结构是 packages/libs/core,必须写成 packages/**packages/*/*

通过合理配置这个文件,你可以将 Monorepo 的依赖管理从“混乱的噩梦”变成“高度可控的工程化利器”。