5月28日 02:10

pnpm 的 overrides 和 resolutions 有什么区别?如何使用?

pnpm.overrides:原生覆盖机制

pnpm.overrides 是 pnpm 原生的依赖覆盖配置,写在 package.jsonpnpm 字段中,也可以写在 pnpm-workspace.yaml 里。

json
// package.json { "pnpm": { "overrides": { "lodash": "^4.17.21", "react": "^18.0.0" } } }
yaml
# pnpm-workspace.yaml overrides: "lodash": "^4.17.21" "react": "^18.0.0"

精确路径覆盖

> 指定只覆盖某个包的依赖,不影响其他包对同一依赖的使用:

json
{ "pnpm": { "overrides": { "webpack>lodash": "^4.17.21", "antd>rc-util": "^5.30.0" } } }

也可以限定只覆盖特定版本的依赖:

json
{ "pnpm": { "overrides": { "minimist@<1.2.6": "^1.2.6" } } }

引用项目直接依赖

$ 前缀引用项目自身声明的依赖版本,避免硬编码版本号导致不一致:

json
{ "dependencies": { "react": "^18.2.0" }, "pnpm": { "overrides": { "react": "$react" } } }

这样所有间接依赖的 react 都会使用项目声明的 ^18.2.0,而不是单独写一个版本。

移除依赖

- 可以把某个依赖从依赖树中移除:

json
{ "pnpm": { "overrides": { "some-package>unused-dep": "-" } } }

这在处理可选依赖或减少安装体积时有用。

替换包

将一个包替换为另一个:

json
{ "pnpm": { "overrides": { "node-sass": "sass", "request": "axios" } } }

对 peerDependencies 生效

pnpm.overrides 会覆盖 peerDependencies 的版本解析。这在统一 React 版本时很常见——某些组件库的 peerDependency 声明了旧版 React,但你希望它们都使用项目中的版本。

resolutions:Yarn 兼容字段

resolutions 是 Yarn 的依赖覆盖字段,pnpm 为了方便从 Yarn 迁移的项目也支持读取它:

json
{ "resolutions": { "lodash": "^4.17.21" } }

resolutions 的局限

resolutions 在 pnpm 中是兼容层,功能比 pnpm.overrides 少很多:

  • 不支持 > 路径指定,只能全局覆盖
  • 不支持 $ 引用直接依赖
  • 不支持 - 移除依赖
  • 不支持 @版本号 限定范围
  • 只能写在 package.json 中,不支持 pnpm-workspace.yaml

两者优先级

pnpm.overridesresolutions 同时存在时,pnpm.overrides 优先级更高。如果同一条目两边都写了,以 pnpm.overrides 为准。

有个已知问题:当 pnpm-workspace.yaml 中写了 overrides 时,package.json 里的 resolutions 可能被忽略而不是合并。所以迁移项目时建议把 resolutions 手动迁移到 pnpm.overrides,而不是两边混用。

区别对比

特性pnpm.overridesresolutions
路径指定(>支持不支持
版本限定(@版本支持不支持
引用直接依赖($支持不支持
移除依赖(-支持不支持
配置位置package.json 或 pnpm-workspace.yaml仅 package.json
peerDependencies 覆盖支持支持
优先级
来源pnpm 原生Yarn 兼容

什么时候用哪个

新项目直接用 pnpm.overrides,不需要考虑 resolutions

从 Yarn 迁移的项目,短期可以保留 resolutions 让项目先跑起来,但应尽快迁移到 pnpm.overrides,否则缺少路径指定和版本限定功能,覆盖精度不够,还可能遇到优先级冲突问题。

常见使用场景

修复传递依赖的安全漏洞

第三方包依赖了有漏洞的旧版本,该包还没更新,你先手动覆盖:

json
{ "pnpm": { "overrides": { "follow-redirects@<1.15.6": "1.15.6" } } }

统一 React 版本

monorepo 里不同包可能依赖不同版本的 React,用 $ 引用统一:

json
{ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "pnpm": { "overrides": { "react": "$react", "react-dom": "$react-dom" } } }

只覆盖某个包的依赖

某个包依赖了不兼容的版本,但你不想影响其他包:

json
{ "pnpm": { "overrides": { "antd>rc-util": "^5.30.0" } } }

验证覆盖效果

修改 overrides 后需要重新安装依赖:

bash
pnpm install

用以下命令确认覆盖是否生效:

bash
# 查看实际安装的版本 pnpm list react # 查看某个依赖被谁引入 pnpm why lodash # 查看完整依赖树 pnpm list --depth=10

注意事项

全局覆盖要谨慎。把所有包的某个依赖强制升到大版本,可能导致不兼容。优先用路径覆盖(>)只影响目标包。

修改 overrides 后记得重新 pnpm install,如果锁文件没更新,可以 pnpm install --force 强制刷新。

标签:PNPM