npm install 跑完不等于依赖装完了——这件事今天把前端项目的真实账全算清楚了

npm install 跑完不等于依赖装完了——这件事今天把前端项目的真实账全算清楚了

每次 npm install 跑完 terminal 跳回光标,我都默认”好了,可以开始写了”。直到有一天我盯着 CI 日志看,发现它花了 42 秒,而隔壁项目只要 6 秒——同一个框架、同样的包,差七倍。

这不是包管理器快慢的问题,是 npm 本身的安装模型在 2026 年的大型项目里已经碰到了结构性瓶颈,而这个瓶颈一直在拖累你的团队,只是没人把它说清楚。


npm 的安装模型:它到底在干什么

npm install 不是简单地把文件拉到 node_modules 里。它要:

  1. 解析整个依赖树(你声明的包 + 它们的 transitive dependencies)
  2. 对每个包查 Registry、下载、处理版本冲突
  3. 把所有包平铺进 node_modules(hoisting 机制)
  4. 执行 postinstall 脚本(如果有)
  5. 写 package-lock.json

每一步都有开销。对一个 500+ 依赖的中型项目,步骤 1-3 本身就可能跑 30-60 秒。这还没算 CI 环境的冷缓存场景。


2026 年真实数据:npm / pnpm / Bun 差多少

用同一套 Next.js 15 + Tailwind v4 项目(847 个直接和传递依赖),清除缓存后测:

场景 npm pnpm Bun
冷装(无缓存) 41s 14.8s 6.2s
暖装(有缓存) 22s 3.1s 3.4s
Lockfile 装(CI 模拟) 19s 2.8s 3.2s
node_modules 磁盘占用 971MB 412MB(实际 180MB) 968MB

数据来源:devtoolbox.blog 2026-07 实测,pkgpulse.com 多方交叉验证。

结论很清楚:Bun 冷装最快,pnpm 暖装和 CI 场景最强,npm 在所有场景都最慢——但 npm v11(随 Node.js 24)比 v10 快了 65%,差距在缩小。


更大的问题:npm 的 hoisting 把 Phantom Dependencies 藏起来了

npm 的 node_modules 是平的。所有包,不管你声明没声明,只要被某个传递依赖带了进来,就都在 node_modules 里躺着。

这意味着:你的代码可以 require("lodash"),但 package.json 里根本没有 lodash——它只是被某个包间接带进来的。开发机跑得好好地,换台机器、升级了一个 transitive dependency,代码崩了,你花了两天才定位到根子。

pnpm 的 node_modules 是严格隔离的。每个包只能访问自己声明的依赖,没声明的 import 进来直接报错。这个问题不是 bug,是架构设计差异,pnpm 把你代码里早就存在的隐患提前暴露了。


磁盘占用:被忽视的真实成本

npm:每个项目复制一份依赖。同一台机器上,10 个项目都用 React 18,磁盘上就存了 10 份 React 18。

pnpm:全局 content-addressable store,存一份,所有项目 hard link 引用。10 个项目省 15-40GB。CI runner 每次 warm cache 命中,install 只要几百毫秒。

这不是小数字。对一个有 20 个微前端的团队,省的是每次 CI 都要重新拉取的那几十秒乘以几十次/天。


pnpm 10 做了什么:2026 年的生产级改进

2026 年的 pnpm 10 有几个对团队直接影响大的更新:

--ignore-scripts 默认开启(CI 模式)
supply chain 攻击最常见的入口就是 postinstall 脚本。pnpm 10 在 CI 环境下默认不执行未声明的脚本,只允许 --only-built-dependencies 白名单里的包跑脚本。

Version Catalogs(catalog:)
monorepo 里多个 package 共享同一个依赖版本,以前靠手动对齐。现在可以:

# pnpm-workspace.yaml
packages:
  - "packages/*"
catalog:
  react: "19.1.0"
  react-dom: "19.1.0"

然后在任意 package.json 里写 "react": "catalog:",统一版本,全局生效。

改进的 --filter 性能
pnpm --filter web build 在大型 monorepo 里的图遍历速度快了 3 倍,对 Turborepo / Nx 配合使用影响明显。


下一步:怎么判断你的项目该换

看 CI 日志:如果 npm install 占了 CI 总时长的 20% 以上,换 pnpm 能直接省出这段时间。

看磁盘占用:一个 20 包以上的 monorepo,pnpm 通常能省出 30-50GB。

看依赖声明:跑 npm ls lodash(lodash 换成任意包),如果这个包不在你项目的 package.json 里但出现在依赖树里——你已经有 phantom dependency 了,pnpm 会强制让你补声明。

迁移成本:几乎为零。删掉 node_modules 和 package-lock.json,执行 corepack enable && corepack prepare pnpm@latest --activate,然后 pnpm install。大多数项目五分钟迁移完。


一句话

npm install 跑完不代表依赖装对了,只代表装完了。2026 年了,工具链已经有更好的选择——只是大多数团队还没意识到自己每天在为此付多少时间账。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 16 阅读