Skip to content
返回维护与 LTS

依赖去重

折叠同一包的重复版本,使你发一份 lodash 而非五份。

为什么

当同一包的五个不同版本进入你的树,你付五份成本:安装时间、包大小、内存、安全面、以及两副本身份不同的 bug(instanceof 破坏因为每副本有自己的原型)。去重把它们折成一份。现代包管理器默认去重(npm 的 hoisting、pnpm 的 symlink),但当两个依赖要求不兼容大版本时冲突 — 此时你得合理重复,要么升级一个消费者解决,要么接受并审计。目标不是零重复(有时不可避免)而是零由浮动范围导致的意外重复。

何时使用

npm ls 显示同包多版本时,或包大小意外膨胀时。

如何做

1. 找重复:npm ls lodash(或 npm ls --all | grep -A2 lodash)— 显示每副本及谁拉它
2. 用 npm explain <path> 看每版本为何在那
3. 若版本接近(同大版本):npm dedupe 自动折叠
4. 若跨大版本:升级要求旧大版本的消费者,或接受分裂
5. 包大小:从根 import 而非嵌套路径;用包分析器(webpack-bundle-analyzer / source-map-explorer)
6. pnpm:设计上去重(单 store、symlink)— monorepo 优先用它
7. 验证:dedupe 后重跑测试(instanceof 身份可能变)并查包大小差

示例

# 找树中所有 lodash 副本
npm ls lodash
# [email protected]
# ├─┬ [email protected]
# │ └── [email protected]  # 旧!
# └── [email protected]    # 你装的

# 4.17.20 为何在那?
npm explain node_modules/foo/node_modules/lodash
# -> [email protected] depends on lodash@^4.17.15

# 去重(折叠 4.17.20 + 4.17.21 -> 4.17.21)
npm dedupe
npm test  # 验证 instanceof 仍工作

# 包分析器看重复成本
npx webpack-bundle-analyzer dist/stats.json
# 若 lodash 在树视图中出现两次,即使 npm dedupe 后
# BUNDLE 中仍有重复 — 升级 foo 到用 [email protected] 的版本。

常见问题

  • ⚠同库两副本破坏 instanceof — 每副本有自己的原型,跨边界 x instanceof Foo 为 false。
  • ⚠跨大版本去重(强塞一个大版本)— 破坏需旧 API 的消费者;仅在大版本内去重。
  • ⚠忽视包重复 — npm dedupe 修 node_modules 但若 import 不同 webpack 仍可能打两副本。

最佳实践

  • ✓每个依赖更新 PR 跑 npm dedupe — 大版本内安全且缩安装 + 包。
  • ✓monorepo 用 pnpm — 其单 store + symlink 设计构造上去重而非事后。
  • ✓加包分析器 CI 检查,若同包在包输出中出现两版本则失败。