1. 核心逻辑
✅ 当无 package-lock.json 时:
npm 会解析 package.json 里的模糊版本范围 (如 ^1.2.3、~1.2.3),下载该范围下的最新版本 (比如 ^1.2.3 会拉 1.x.x 最新版,~1.2.3 会拉 1.2.x 最新版);
如果 package.json 写的是精确版本 (如 1.2.3 无 ^/~),即使没有 lock 文件,也会下载该精确版本(但这种情况极少,因为大家通常用模糊范围)。
✅ 当有 package-lock.json 时:
npm 会忽略 package.json 的模糊范围 ,强制安装 lock 文件中记录的精确版本(包括直接依赖 + 所有间接依赖),且依赖的下载源、哈希值都要匹配,确保"一模一样"。
2. 补充两个易忽略的细节
(1)lock 文件不是"一成不变"的
如果手动修改了 package.json 的依赖版本范围(比如把 ^4.17.0 改成 ^4.18.0),再执行 npm install,npm 会重新解析新的范围,下载对应最新版,并更新 lock 文件到新的精确版本------此时 lock 文件会"跟着新范围走",而非死守旧版本。
(2)npm update 会主动突破 lock 文件
如果执行 npm update 包名(或不带包名更新所有),npm 会忽略 lock 文件,按 package.json 的模糊范围下载最新版,并更新 lock 文件到新版本。
这也符合逻辑:npm install 是"保一致性",npm update 是"主动升级"。
举个例子强化理解
| 场景 | package.json 依赖 | 无 lock 文件 | 有 lock 文件(记录 4.17.21) |
|---|---|---|---|
| 正常 npm install | lodash: ^4.17.0 | 下载 4.x 最新版(如 4.18.0) | 强制下载 4.17.21 |
| 改 package.json 为 ^4.18.0 后 npm install | lodash: ^4.18.0 | 下载 4.18.x 最新版 | 更新 lock 文件,下载 4.18.x 最新版 |
| 执行 npm update lodash | lodash: ^4.17.0 | 下载 4.x 最新版 | 更新 lock 文件,下载 4.x 最新版 |