关于 audit-and-reduce-dependencies
用于审计和缩减 pnpm 工作区中 JavaScript 依赖规模的技能。它先检查供应链安全,再衡量锁文件影响,并谨慎实施和验证依赖变更。
主要功能
- 01变更前运行 check-npm
- 02识别未使用的直接依赖
- 03整理工作区间的版本重复
- 04测量传递依赖闭包
- 05评估升级和内联候选项
- 06验证变更并报告影响
适用场景
- 01删除已确认未使用的包
- 02减少重复的依赖版本
- 03按锁文件成本排列依赖优先级
- 04评估 pnpm 工作区中的低风险升级
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ grafana/ skills --skill audit-and-reduce-dependencies安装后在 Claude Code 中输入/audit-and-reduce-dependencies确认已加载。
详细介绍
审计并精简依赖
缩减 JavaScript 依赖体量。仅使用 pnpm。保留锁文件、工作区布局和依赖版本范围风格,除非有充分理由需要更改。
对于 GitHub Actions 工作流的分类(操作选择、权限、固定版本),请使用专门的工作流审计,而不要使用以下报告格式(只有在发现涉及 pnpm 安装策略的问题时,才报告工作流文件和步骤)。
工作流
- 加固关卡:运行
/check-npm(只读)。参见 check-npm。 - 确定基线。
- 移除未使用的直接依赖。
- 在单体仓库中统一直接依赖版本。
- 按传递依赖锁文件闭包对直接依赖排序。
- 利用闭包数据查找低风险的次要版本/补丁版本升级。
- 利用闭包数据查找值得内联的简单依赖。
- 检查 e18e 对替换/移除的建议。
- 重新安装、验证并报告实际影响。
步骤 0:加固关卡(/check-npm)
在修改清单或锁文件前,先运行 /check-npm。
- 如果任何检查失败:报告表格和修复片段;清理期间不要放宽
pnpm-workspace.yaml、.npmrc、CI 安装标志或 Renovate 的等待期限门槛。 - 不要将完整加固配置粘贴到此工作流中——
/check-npm负责版本阈值、脚本策略、Git 依赖协议和最短发布等待时间。 - 如果用户只要求加固(而非精简),运行完
/check-npm后即可停止,除非用户也希望进行清理。
**pnpm 11+:**脚本和发布等待期限策略位于 pnpm-workspace.yaml,而非 .npmrc 或 package.json#pnpm(pnpm 11 不再读取 package.json#pnpm 字段)。提出配置建议前,请根据已安装的 pnpm 主版本核实每个键。切勿添加不受支持的键。清理期间不要缩短现有的 minimumReleaseAge(或组织等效配置)。
依赖分类
对于每个非简单的直接依赖(尤其是完成步骤 4–7 后),指定一个标签:
| 标签 | 含义 |
|---|---|
| 保留 | 必需;其传递依赖成本值得承担;维护良好。 |
| 替换为更优方案 | 必需;存在维护更好或更安全的替代方案。 |
| 替换为内部实现 | 必需;外部风险足以成为内部实现的理由。 |
| 移除 | 可以删除或内联(步骤 6)。 |
| 需要用户审核 | 用途不明确、涉及策略权衡,或需要人工验证变更。 |
替代方案和新增直接依赖
- 未经用户明确批准,不得新增直接依赖(包括替换依赖)。
- 在效果相当时,优先选择移除(内联/原生 API),而非替换为更优方案。
- 对于替换为更优方案:说明原因(维护情况、安全性、依赖树更小);优先选择由可信维护者维护、积极维护且广泛采用的软件包。
- 遵循仓库的
minimumReleaseAge/Renovate 门槛;命令级别的 72 小时新鲜度只是下限,并不意味着可以绕过更严格的配置。
pnpm 与供应链
确认仓库使用 pnpm:根目录 package.json 中存在 pnpm-lock.yaml、pnpm-workspace.yaml,和/或 packageManager / devEngines.packageManager.name 设置为 pnpm。如果未使用 pnpm,请停止——不要在清理过程中迁移包管理器。
如仓库有安装策略,请遵循(例如 pnpm install --frozen-lockfile --ignore-scripts)。
| 操作 | 命令 |
|---|---|
| 安装/更新锁文件 | pnpm install --ignore-scripts(以及仓库要求的标志,例如 --frozen-lockfile) |
| 移除直接依赖 | pnpm remove <pkg> --ignore-scripts |
| 添加/更新直接依赖 | pnpm add <pkg>@<version> --ignore-scripts |
| 说明依赖 | pnpm why <pkg> |
| 整理锁文件 | pnpm dedupe(然后如果锁文件有更改,运行 pnpm install --ignore-scripts) |
| 过期/版本信息 | pnpm outdated <pkg> |
| 一次性工具 | pnpm --config.ignore-scripts=true dlx <pkg>@<version> <args...>(固定版本;如果工具在锁文件中,优先使用 pnpm exec) |
生命周期脚本:除非用户在同一条消息中明确写出 allow scripts,否则运行 pnpm install、pnpm add 和 pnpm remove 时始终添加 --ignore-scripts(并说明将运行哪些脚本及其风险)。对于 pnpm dlx,它不接受直接传入 --ignore-scripts——请使用 pnpm --config.ignore-scripts=true dlx(dlx 后的标志会传给执行的二进制文件)。如果某个依赖确实需要构建脚本(例如原生模块),先在不运行脚本的情况下完成操作,然后询问是否运行指定的手动重建命令(例如 pnpm rebuild <pkg>)。
新鲜度检查(≥ 72 小时)——在运行任何会添加或升级指定包版本的命令之前(pnpm add、使用新/升级后直接依赖版本的 pnpm dlx),必须进行检查。不要求对不含新包参数的普通 pnpm install/pnpm remove 进行检查。
对每个直接指定的包:
curl -s https://registry.npmjs.org/<package-name>- 确定版本:固定版本
[email protected]→ 使用该版本;版本范围/latest/未指定 → 使用dist-tags.latest - 查看
time["<version>"] - 如果发布距今不到 72 小时 → 停止。告知用户包名、版本和精确时间。建议固定到较早且已知稳定的版本,除非用户写出 override freshness check。
@grafana/*范围内的包不受新鲜度检查限制;但仍须使用--ignore-scripts。
新鲜度检查未通过后,未经用户批准,不要改用其他版本。
安全规则
- 分小批次操作,以便审查锁文件差异。
- 切勿盲目信任未使用依赖分析工具;请核实导入、配置文件、脚本、生成代码钩子、框架约定、插件名称、CLI 和动态导入。
- 可以编写脚本和解析程序,以核实
package.json和锁文件中的依赖记录。 - 将
peerDependencies、optionalDependencies、包的二进制文件用法、测试夹具和已发布的包清单视为高风险项。 - 除非已证明替代方案完全等效,否则不要移除或内联用于安全、解析、加密、Unicode、URL 处理、日期/时间、国际化或平台兼容性的依赖。
- 不要在清理过程中切换包管理器、删除
pnpm-lock.yaml或重写工作区结构。 - 将
pnpm dedupe视为可能改变行为的操作;检查锁文件差异,并在保留结果前进行有针对性的验证。 - 测量操作前后的情况:直接依赖数量、锁文件行数或条目数、包数量,以及可获取时的预估
node_modules大小。
第 1 步:建立基线
收集:
- 所有
package.json文件和工作区边界(pnpm-workspace.yaml)。 pnpm-lock.yaml、pnpm-workspace.yaml中的安全设置(minimumReleaseAge、strictDepBuilds、blockExoticSubdeps、allowBuilds),以及.npmrc/ CI 标志中的安装策略(例如--frozen-lockfile、--ignore-scripts)。- 按清单部分列出直接依赖名称:
dependencies、devDependencies、peerDependencies、optionalDependencies。 - scripts、CI 或仓库文档中现有的验证命令。
- CI 抽查(
.github/workflows或同等位置):安装应使用pnpm install --frozen-lockfile,并确保脚本阻止策略与工作区配置一致。标记每次运行都会重新生成锁文件的工作流。 - Renovate / Dependabot(如果存在):记录 npm 包的
minimumReleaseAge;清理时不要降低该值。
记录基线指标:git status --short、wc -l pnpm-lock.yaml。如果已安装 node_modules,请使用适合相应平台的工具估算其占用空间。锁文件缩减是首要指标,不要依赖 node_modules 是否存在。
第 2 步:移除未使用的直接依赖
不安全的直接依赖协议——扫描所有工作区 package.json 的依赖部分。标记值不属于以下类型的条目:semver 范围、workspace:、patch:,或指向 semver 的 npm: 别名。标记 git: / github: / tarball URL / user/repo 简写 / file: / link: / exec: 等(与 /check-npm 的允许列表相同)。不要悄悄移除标记的条目;应报告并留待单独的安全加固 PR 处理,除非用户要求修复这些条目。
将静态分析器作为起点,而非依据(knip、depcheck 或仓库原生工具)。工具未安装时,使用固定版本的 pnpm --config.ignore-scripts=true dlx <tool>@<version> <args...> 运行(先检查固定版本是否最新)。
对每个候选项:
- 在代码、配置、包脚本、构建工具、测试和文档中搜索包名及已知导入路径。
- 检查它是否为已发布包清单、peer 合约、插件加载器、CLI 命令或动态
require/import所必需。 - 仅在确实不再使用时移除。
- 运行
pnpm install --ignore-scripts(加上仓库标志)并进行针对性验证。
如果依赖仅在脚本或配置中使用,请考虑在 dependencies 和 devDependencies 之间移动,而不是移除。
第 3 步:统一 monorepo 中的直接依赖版本
查找多个包清单中声明了不同版本/范围的同一直接依赖。优先采用现有策略:精确固定版本、caret 范围、catalog/协议用法、工作区协议或集中约束。
- 使用
syncpack list-mismatches或同等工具进行排查。 - 如果多个包可以共用同一兼容版本,则统一直接依赖范围。
- 在添加
pnpm.overrides之前,优先统一清单级别的版本。 - 仅在需要统一传递依赖版本或修复安全问题时使用
pnpm.overrides,并记录原因。
统一后,运行 pnpm install --ignore-scripts(加上仓库标志)并检查清单和锁文件的差异。然后考虑运行 pnpm dedupe——谨慎应用;它可能会改变传递依赖解析结果。
第 4 步:评估传递依赖锁文件闭包
针对每个重要的直接依赖,估算其闭包:从该依赖可到达的传递依赖锁文件条目。
报告以下两项:
- 总闭包:从该依赖可到达的所有包。
- 独占闭包:移除此依赖后会消失,且不会被其他直接依赖保留的包。
优先采用确定性测量:
- 保存锁文件基线指标。
- 从所属清单中临时移除一个直接依赖。
- 运行
pnpm install --ignore-scripts(加上仓库标志)。 - 测量锁文件行数/条目减少量和包数量减少量。
- 在测量下一个依赖之前,还原清单和
pnpm-lock.yaml(例如,git checkout -- <manifest> pnpm-lock.yaml)。
对体积较大的传递依赖包使用 pnpm why <pkg>。按影响和风险排序,而不只是看原始大小。
第 5 步:寻找低风险、高影响的升级
利用闭包排名,锁定更新到较新次要版本或补丁版本后能减少传递依赖的直接依赖项。
对于每个候选项:
- 使用
pnpm outdated检查可用的非主版本。 - 查看变更日志/发行说明,了解依赖树的变化。
- 检查目标版本的新鲜度,然后一次升级一个依赖项或紧密相关的一组依赖项(
pnpm add <pkg>@<version> --ignore-scripts)。 - 运行
pnpm install --ignore-scripts(加上仓库所需标志),并比较闭包指标。 - 运行有针对性的测试及相关构建/类型检查命令。
除非用户明确接受迁移风险,否则避免升级主版本。
第 6 步:内联简单用法
利用闭包排名,找出用法简单明了、但传递依赖开销较大的直接依赖项。
仅在以下条件全部满足时才内联:
- 用法很少,且容易完整界定。
- 等效代码比保留依赖项更简洁或更清晰。
- 测试已覆盖相应行为,或可以通过少量特征测试加以覆盖。
- 该依赖项并非用于处理跨平台、安全、解析、Unicode、区域设置或规范合规方面的边缘情况。
所需行为简单时,优先使用原生 API,而不是新增替代依赖项。
第 7 步:应用 e18e 指南
# Pin @e18e/cli@<version> after freshness check; disable scripts on the dlx install
pnpm --config.ignore-scripts=true dlx @e18e/cli@<version> analyze
pnpm --config.ignore-scripts=true dlx @e18e/cli@<version> migrate --dry-run
另请查看 https://e18e.dev/docs/replacements/。将建议视为候选项,而非必须执行的要求;请验证打包/运行时行为并运行测试。只有在用户批准后,才将 e18e 替换方案归类为 Replace-with-Better。
报告
总结结果并提供测得的影响:
/check-npm结果(PASS/FAIL 摘要;若 FAIL,附上修复链接)。- 已移除或转为其他类型的直接依赖项。
- 已去重的直接依赖版本。
- 锁文件行数/条目数的减少情况。
- 可用时估算的包或
node_modules缩减量。 - 延后处理的高影响候选项及原因(包括等待批准的替换方案)。
- 基线检查发现的不安全协议/CI/Renovate 问题(如有)。
- 运行的验证命令及结果。
- 供应链:已检查新鲜度(或豁免)的版本、所有安装/添加命令均使用
--ignore-scripts,以及pnpm dlx使用--config.ignore-scripts=true。
如果某项移除依赖的是静态分析而非运行时覆盖,请明确指出风险。
报告格式
仅用于依赖清理发现,不用于 GitHub Actions 工作流分类。
对每项发现:
- 证据:包名及版本/范围;清单文件路径及所属部分;支持信号(导入位置、
pnpm why、knip/depcheck 发现、闭包度量、/check-npm条目,或仅限 pnpm install 策略的工作流文件及步骤)。 - 决定:选择一个 Dependency triage 标签。
- 拟议变更:给出确切的清单/锁文件命令或编辑内容。若尚未应用,需明确说明。
- 理由:体积(独占/总闭包)、供应链、维护或验证风险。
- 需要用户审核:需要运行的测试/构建/类型检查;peer/插件/CLI 使用方;已发布包或动态导入风险;以及对 Replace-with-Better 或任何新直接依赖项的事先批准。
对于非简单发现,每个包(或每项协议/CI 发现)使用一个区块,而不是只用一行概述。