包管理器挖掘🪦
Source: Dev.to

包管理器的历史
npm 的问题点
-
重复的依赖下载
依赖会依赖其他依赖,层层递进。即使包名和版本相同,npm v1、v2 仍会重复下载,导致安装时间变长。 -
安装方式导致的请求瀑布(request waterfall)
由于顺序解析并下载依赖,无法并行下载。
1️⃣ 依赖 1 安装 → 检查 package.json → 依赖 2 安装 → …
这一过程按顺序进行,使得安装时间延长。 -
无法锁定包版本
没有 lockfile,各开发者使用的版本各不相同。package.json只固定^(主版本)或~(次版本),所有人都会使用不同的版本进行开发和发布,导致问题难以复现。
read package1/package.json
└─ find package2
└─ download package2
└─ read package2/package.json
└─ find package3
└─ download package3
read package.json → find package → download package 按顺序发生,使得 npm install 时间变长。
解决下载瓶颈的 yarn classic
-
依赖缓存
当相同的包名·版本出现重复时,使用缓存来缩短下载时间。重复的包会通过提升(hoisting)移动到上层目录。 -
先绘制依赖图再并行下载
fetch package metadata from registry (JSON)
→ read dependencies from metadata
→ resolve versions (lockfile 优先)
→ 完成整个 dependency graph
Download packages in parallel
- 通过 lockfile 锁定包版本
lockfile 中写明到补丁版本,所有人都在相同的依赖版本上进行开发、CI、部署,错误复现难度大幅降低。
yarn classic 的问题点
隐式依赖导致的项目依赖崩溃
Node.js 在寻找模块时会从当前目录向上查找 /node_modules/package。由于提升,未在 package.json 中声明的包会被放到最上层的 /node_modules,从而可以被 import,这类依赖被称为 phantom dependencies(幽灵依赖)。
磁盘 I/O 导致的模块解析速度下降
大量目录扫描产生磁盘 I/O,导致 yarn dev、yarn build 时开发服务器启动和构建时间变慢。
import lodash
→ filesystem walk-up
→ /node_modules/lodash 在吗? OK
解决隐式依赖的 yarn berry
用映射表文件指明位置
在 .pnp.cjs 文件中声明每个依赖的路径,并覆盖 Node.js 的 require() 行为,使其参考 .pnp.cjs 来寻找依赖路径,从而阻断隐式依赖的产生。
用单个文件处理所有逻辑,避免大量磁盘 I/O
因为 require() 被覆盖,重复的磁盘 I/O 消失。
import lodash
→ .pnp.cjs 加载
→ 检查当前包的 dependency graph
→ 在 package.json 中声明了吗?
❌ No → 立即报错