依赖去重
折叠同一包的重复版本,使你发一份 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 检查,若同包在包输出中出现两版本则失败。