workspace-audit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWorkspace Audit (pnpm 10+)
工作区审计(pnpm 10+)
Purpose
审计目的
Analyze pnpm monorepo workspace configuration to:
- Optimize dependency management
- Check workspace protocol and catalog usage
- Audit build hook and dependency rule configuration
- Identify cargo-culted or outdated settings
分析pnpm单体仓库工作区配置,以:
- 优化依赖管理
- 检查workspace协议和目录的使用情况
- 审计构建钩子和依赖规则配置
- 识别盲目照搬或过时的设置
When to Use This Skill
适用场景
Use when the user asks to:
- "Audit my monorepo"
- "Check workspace configuration"
- "Optimize pnpm workspace"
- "Review monorepo setup"
Trigger phrases: "workspace audit", "monorepo", "pnpm workspace", "workspaces"
当用户提出以下需求时使用:
- "审计我的单体仓库"
- "检查工作区配置"
- "优化pnpm工作区"
- "审核单体仓库设置"
触发关键词:"workspace audit"、"monorepo"、"pnpm workspace"、"workspaces"
Workflow
工作流程
Step 1: Identify Workspace Type
步骤1:识别工作区类型
bash
cat pnpm-workspace.yaml 2>/dev/null
cat package.json | jq '.packageManager, .engines'
ls -la nx.json turbo.json 2>/dev/nullCheck the field — it tells you the exact pnpm version. Audit advice below assumes pnpm 10+; call out version-gated settings when the project is on an older minor.
packageManagerbash
cat pnpm-workspace.yaml 2>/dev/null
cat package.json | jq '.packageManager, .engines'
ls -la nx.json turbo.json 2>/dev/null检查字段——它会显示确切的pnpm版本。以下审计建议基于pnpm 10+;如果项目使用旧版本,需标注受版本限制的设置。
packageManagerStep 2: Analyze Workspace Structure
步骤2:分析工作区结构
yaml
undefinedyaml
undefinedGood: Explicit patterns
推荐:明确的匹配模式
packages:
- 'packages/*'
- 'apps/*'
- 'tools/*'
packages:
- 'packages/*'
- 'apps/*'
- 'tools/*'
Avoid: Too broad
不推荐:范围过宽
packages:
- '**'
**Config-only workspace:** A `pnpm-workspace.yaml` without a `packages:` field is valid for single-package projects that still want catalog, overrides, or build hook config.packages:
- '**'
**仅配置型工作区:** 不含`packages:`字段的`pnpm-workspace.yaml`对仍需使用目录、覆盖或构建钩子配置的单包项目有效。Step 3: Check Workspace Protocol Usage
步骤3:检查workspace协议使用
Good:
json
{
"dependencies": {
"@myorg/shared": "workspace:*",
"@myorg/utils": "workspace:^"
}
}Audit:
- Flag hardcoded versions () for internal packages — should use
"^1.0.0"workspace:*
bash
undefined规范用法:
json
{
"dependencies": {
"@myorg/shared": "workspace:*",
"@myorg/utils": "workspace:^"
}
}审计要点:
- 标记内部包的硬编码版本(如)——应使用
"^1.0.0"workspace:*
bash
undefinedFind all package.json files and check for org-scoped internal refs
查找所有package.json文件并检查组织范围内的内部引用
fd -t f 'package.json' packages apps | xargs grep -l '@myorg/'
undefinedfd -t f 'package.json' packages apps | xargs grep -l '@myorg/'
undefinedStep 4: Check Dependency Hoisting
步骤4:检查依赖提升
Pnpm uses isolated by default — no hoisting. Check for overrides:
node_modules.npmrcini
hoist=true # enables hoisting to .pnpm/node_modules
shamefully-hoist=true # makes node_modules flat like npm — last resortAudit: is a red flag. It bypasses pnpm's isolation model. Should only be present if a specific tool requires it, with a comment explaining why.
shamefully-hoist=truebash
pnpm dedupe --checkPnpm默认使用隔离的——无依赖提升。检查中的覆盖设置:
node_modules.npmrcini
hoist=true # 启用依赖提升至.pnpm/node_modules
shamefully-hoist=true # 将node_modules设置为类似npm的扁平结构——最后手段审计要点: 是危险信号。它会绕过pnpm的隔离模型。仅当特定工具需要时才可设置,并需添加注释说明原因。
shamefully-hoist=truebash
pnpm dedupe --checkStep 5: Check Catalog Configuration
步骤5:检查目录配置
Catalog definition
目录定义
yaml
undefinedyaml
undefinedpnpm-workspace.yaml
pnpm-workspace.yaml
catalog:
react: ^19.0.0
react-dom: ^19.0.0
typescript: ^5.0.0
vite: ^6.0.0
vitest: ^3.0.0
npm: prefix aliases a name to a different package implementation
vite: npm:@org/custom-vite-fork@^1.0.0
undefinedcatalog:
react: ^19.0.0
react-dom: ^19.0.0
typescript: ^5.0.0
vite: ^6.0.0
vitest: ^3.0.0
npm: 前缀将名称别名到不同的包实现
vite: npm:@org/custom-vite-fork@^1.0.0
undefinedUsage in packages
包中的用法
json
{
"dependencies": { "react": "catalog:", "react-dom": "catalog:" },
"devDependencies": { "vite": "catalog:", "vitest": "catalog:", "typescript": "catalog:" }
}json
{
"dependencies": { "react": "catalog:", "react-dom": "catalog:" },
"devDependencies": { "vite": "catalog:", "vitest": "catalog:", "typescript": "catalog:" }
}Audit checks
审计检查
- All shared deps should use , not hardcoded versions in individual packages
catalog: - Avoid in catalog entries — defeats reproducibility and conflicts with
@latestminimumReleaseAge - aliases must be intentional and version-pinned (not
npm:)@latest - (10.12.1+) — enforces that all packages use
catalogMode: forcefor any dep in the catalog; flag if shared deps exist but this is not enabledcatalog: - (10.15+) — automatically removes stale catalog entries on install; flag if catalog has grown large and this is not set
cleanupUnusedCatalogs: true
- 所有共享依赖应使用,而非在单个包中硬编码版本
catalog: - 避免在目录条目中使用——这会破坏可复现性,并与
@latest冲突minimumReleaseAge - 别名必须是有意设置的,且版本固定(不能是
npm:)@latest - (10.12.1+)——强制所有包对目录中的任何依赖使用
catalogMode: force;如果存在共享依赖但未启用该设置,需标记catalog: - (10.15+)——安装时自动删除过时的目录条目;如果目录已变大但未设置该值,需标记
cleanupUnusedCatalogs: true
Step 6: Check Build Order
步骤6:检查构建顺序
Verify cross-package dependencies are declared:
json
{
"name": "@myorg/app",
"dependencies": {
"@myorg/ui": "workspace:*",
"@myorg/utils": "workspace:*"
}
}bash
pnpm -r run build # respects topological order
turbo run build --dry-run # if Turbo is used验证跨包依赖已声明:
json
{
"name": "@myorg/app",
"dependencies": {
"@myorg/ui": "workspace:*",
"@myorg/utils": "workspace:*"
}
}bash
pnpm -r run build # 遵循拓扑顺序
turbo run build --dry-run # 如果使用TurboStep 7: Check Build Hook Configuration
步骤7:检查构建钩子配置
Build hook config belongs in , not .
pnpm-workspace.yamlpackage.json构建钩子配置应放在中,而非。
pnpm-workspace.yamlpackage.jsonpnpm 10.0–10.25
pnpm 10.0–10.25
yaml
undefinedyaml
undefinedBlacklist: skip post-install scripts for these
黑名单:跳过这些包的安装后脚本
ignoredBuiltDependencies:
- unrs-resolver
- sharp
ignoredBuiltDependencies:
- unrs-resolver
- sharp
Whitelist: only these packages may run post-install scripts
白名单:仅这些包可运行安装后脚本
onlyBuiltDependencies:
- esbuild
Don't use both together — pick the model that fits the project's security posture.onlyBuiltDependencies:
- esbuild
不要同时使用两者——选择符合项目安全策略的模型。pnpm 10.26+ — allowBuilds
allowBuildspnpm 10.26+ — allowBuilds
allowBuildsReplaces and with a single explicit map:
ignoredBuiltDependenciesonlyBuiltDependenciesyaml
allowBuilds:
esbuild: true
unrs-resolver: false
sharp: false用单个显式映射替代和:
ignoredBuiltDependenciesonlyBuiltDependenciesyaml
allowBuilds:
esbuild: true
unrs-resolver: false
sharp: falsestrictDepBuilds
(10.3+)
strictDepBuildsstrictDepBuilds
(10.3+)
strictDepBuildsFails the install if any dependency tries to run a build script that isn't covered by the allow/ignore config:
yaml
strictDepBuilds: trueAudit: If neither / nor is set, build scripts run unchecked — flag as a supply-chain risk.
onlyBuiltDependenciesallowBuildsstrictDepBuilds如果任何依赖尝试运行未被允许/忽略配置覆盖的构建脚本,安装将失败:
yaml
strictDepBuilds: true审计要点: 如果未设置/或,构建脚本将不受检查——标记为供应链风险。
onlyBuiltDependenciesallowBuildsstrictDepBuildsStep 8: Check Dependency Rules
步骤8:检查依赖规则
All of these belong in .
pnpm-workspace.yaml所有这些规则都应放在中。
pnpm-workspace.yamlminimumReleaseAge (10.16+) / minimumReleaseAgeExclude (10.17+)
minimumReleaseAge (10.16+) / minimumReleaseAgeExclude (10.17+)
Prevents installing packages published less than N minutes ago:
yaml
minimumReleaseAge: 1440 # 24 hours
minimumReleaseAgeExclude:
- '@typescript/native-preview' # bleeding-edge, exempt by designAudit: missing entirely is a risk signal. (24h) is a reasonable default.
1440防止安装发布时间不足N分钟的包:
yaml
minimumReleaseAge: 1440 # 24小时
minimumReleaseAgeExclude:
- '@typescript/native-preview' # 前沿版本,特意豁免审计要点:完全未设置该值是风险信号。(24小时)是合理的默认值。
1440trustPolicy (10.21+)
trustPolicy (10.21+)
Enforces publisher trust levels — complements with a signature/provenance check:
minimumReleaseAgeyaml
trustPolicy: audit # audit | warn | off
trustPolicyExclude: # (10.22+) exempt specific packages
- '@myorg/internal'
trustPolicyIgnoreAfter: 525600 # (10.27+) ignore trust for packages older than 1 yearAudit: flag if is absent and the project has set — both are supply-chain controls that complement each other.
trustPolicyminimumReleaseAge强制实施发布者信任级别——通过签名/来源检查补充:
minimumReleaseAgeyaml
trustPolicy: audit # audit | warn | off
trustPolicyExclude: # (10.22+) 豁免特定包
- '@myorg/internal'
trustPolicyIgnoreAfter: 525600 # (10.27+) 忽略发布超过1年的包的信任检查审计要点:如果项目已设置但未设置,需标记——两者都是互补的供应链控制措施。
minimumReleaseAgetrustPolicyblockExoticSubdeps (10.26+)
blockExoticSubdeps (10.26+)
Restricts git, file, and URL dependencies to direct dependencies only — prevents transitive exotic sources:
yaml
blockExoticSubdeps: trueAudit: flag if git or file deps appear in the dependency tree and this is not enabled.
限制git、文件和URL依赖仅为直接依赖——防止传递性的非常规来源:
yaml
blockExoticSubdeps: true审计要点:如果依赖树中出现git或文件依赖但未启用该设置,需标记。
overrides
overrides
Pin or replace transitive dependency versions, including references:
catalog:yaml
overrides:
vite: 'catalog:' # force transitive consumers to use the catalog version
vitest: 'catalog:'
lodash: '^4.17.21' # pin vulnerable transitive depAudit: check for outdated pinned versions, or missing overrides where catalog versions are inconsistent across the dep tree.
固定或替换传递性依赖版本,包括引用:
catalog:yaml
overrides:
vite: 'catalog:' # 强制传递性消费者使用目录版本
vitest: 'catalog:'
lodash: '^4.17.21' # 固定有漏洞的传递性依赖审计要点:检查过时的固定版本,或目录版本在依赖树中不一致时是否缺少覆盖设置。
peerDependencyRules
peerDependencyRules
Suppress spurious peer dep warnings — common with custom toolchain forks:
yaml
peerDependencyRules:
allowAny:
- vite
- vitest
allowedVersions:
vite: '*'
vitest: '*'Audit: flag — that's too broad. Specific package names are fine.
allowAny: ['*']抑制虚假的peer依赖警告——常见于自定义工具链分支:
yaml
peerDependencyRules:
allowAny:
- vite
- vitest
allowedVersions:
vite: '*'
vitest: '*'审计要点:标记——范围过宽。指定具体包名称是可行的。
allowAny: ['*']Step 9: Check .npmrc
步骤9:检查.npmrc
Most settings commonly copy-pasted into projects are redundant defaults or belong elsewhere:
.npmrc| Setting | Issue |
|---|---|
| Default in pnpm 9+ — redundant |
| Default in pnpm 10 — redundant; use |
| Superseded by |
| Not default; use only if you want hard failures on peer mismatches — evaluate per-project |
Audit: flag entries that are no-ops or have better homes.
.npmrcValid reasons to use :
.npmrcini
undefined大多数被复制粘贴到项目中的设置是冗余的默认值,或应放在其他位置:
.npmrc| 设置 | 问题 |
|---|---|
| pnpm 9+中的默认值——冗余 |
| pnpm 10中的默认值——冗余;在CI中使用 |
| 已被 |
| 非默认值;仅当希望peer依赖不匹配时强制失败才使用——需按项目评估 |
审计要点:标记无作用或有更合适存放位置的.npmrc条目。
使用.npmrc的合理场景:
ini
undefinedPrivate registry for scoped packages
组织范围内包的私有仓库
@myorg:registry=https://npm.myorg.com/
@myorg:registry=https://npm.myorg.com/
Windows cross-platform script compatibility
Windows跨平台脚本兼容性
shell-emulator=true
undefinedshell-emulator=true
undefinedStep 10: Check for Common Issues
步骤10:检查常见问题
Inconsistent dep versions (not in catalog)
不一致的依赖版本(未在目录中)
bash
npx syncpack list-mismatchesbash
npx syncpack list-mismatchesCircular dependencies
循环依赖
bash
npx madge --circular packages/*/srcbash
npx madge --circular packages/*/srcStale catalog entries
过时的目录条目
Set in , or run:
cleanupUnusedCatalogs: truepnpm-workspace.yamlbash
pnpm install # removes stale entries if cleanupUnusedCatalogs is enabled在中设置,或运行:
pnpm-workspace.yamlcleanupUnusedCatalogs: truebash
pnpm install # 如果启用cleanupUnusedCatalogs,会删除过时条目Step 11: Generate Report
步骤11:生成报告
markdown
undefinedmarkdown
undefinedWorkspace Audit Report
工作区审计报告
Structure
结构
- pnpm version: 10.x
- Packages: 5 (3 apps, 2 libs)
- pnpm版本:10.x
- 包数量:5个(3个应用,2个库)
Workspace Protocol
Workspace协议
- workspace:* used for all internal deps
- 2 packages use hardcoded versions for internal deps
- 所有内部依赖使用workspace:*
- 2个包对内部依赖使用硬编码版本
Catalog
目录
- Shared deps pinned in catalog
- @latest used in 1 catalog entry — defeats reproducibility
- catalogMode not set — consider force to enforce catalog usage
- 共享依赖在目录中固定
- 1个目录条目使用@latest——破坏可复现性
- 未设置catalogMode——考虑启用force以强制使用目录
Build Hooks
构建钩子
- onlyBuiltDependencies configured in pnpm-workspace.yaml
- Build hook config found in package.json — move to pnpm-workspace.yaml
- strictDepBuilds not set — unchecked build scripts
- 在pnpm-workspace.yaml中配置了onlyBuiltDependencies
- 在package.json中发现构建钩子配置——需移至pnpm-workspace.yaml
- 未设置strictDepBuilds——构建脚本不受检查
Dependency Rules
依赖规则
- minimumReleaseAge not set (supply-chain risk)
- trustPolicy not set (complements minimumReleaseAge)
- overrides pin transitive deps to catalog versions
- blockExoticSubdeps not set — exotic transitive sources unchecked
- 未设置minimumReleaseAge(供应链风险)
- 未设置trustPolicy(补充minimumReleaseAge)
- 覆盖设置将传递性依赖固定为目录版本
- 未设置blockExoticSubdeps——传递性非常规来源不受检查
Configuration
配置
- .npmrc is minimal — no cargo-culted settings
- prefer-frozen-lockfile=true in .npmrc — already the default, remove it
- .npmrc配置简洁——无盲目照搬的设置
- .npmrc中存在prefer-frozen-lockfile=true——已是默认值,需删除
Recommendations
建议
- Set minimumReleaseAge: 1440 in pnpm-workspace.yaml
- Set trustPolicy: audit alongside minimumReleaseAge
- Move build hook config from package.json to pnpm-workspace.yaml
- Enable strictDepBuilds: true
- Replace hardcoded internal dep versions with workspace:*
See `references/workspace-template.md` for an optimized pnpm-workspace.yaml template.- 在pnpm-workspace.yaml中设置minimumReleaseAge: 1440
- 配合minimumReleaseAge设置trustPolicy: audit
- 将构建钩子配置从package.json移至pnpm-workspace.yaml
- 启用strictDepBuilds: true
- 将内部依赖的硬编码版本替换为workspace:*
查看`references/workspace-template.md`获取优化后的pnpm-workspace.yaml模板。