为什么 CI/CD 缓存了 node_modules之后遇到一点package改动构建还是很慢?

101 阅读2分钟

在前端团队优化 CI/CD 流水线时,很多人会尝试「缓存 node_modules」来加快依赖安装。但实际用下来,大家经常发现——加新依赖或者依赖有变动时,安装依然很慢,且维护和管理成本极高。这是因为 node_modules 缓存存在一些技术陷阱和效率瓶颈。


node_modules 缓存:看似高效,实则暗藏风险

1. node_modules 不是增量结构

  • Yarn/NPM/PNPM 的 node_modulespackage.json / lockfile 紧密相关,并不是可增量合并的目录。
  • 一旦依赖树有变化,之前缓存下来的 node_modules 结构就会和当前项目声明(package.json/yarn.lock)不一致。
  • 包管理器因此会做校验、删除残留老依赖,安装新包、修复依赖树。实际效果往往接近“全量 reinstall”,老 cache 利用不高

2. 慢的根源不仅仅在 network I/O

  • 你加包或升级依赖后,安装流程往往还需:
    • 校验旧 cache 和 lockfile 差异
    • 下载新包,删除无用包,解压并重写依赖
    • 重新执行所有 postinstall、build 脚本(如 node-gyp、canvas、sharp 等会重新编译 C++ 插件)
  • /** 对于大型 monorepo,解包、I/O、脚本构建非常耗时,哪怕 CI 服务器配有 SSD 也不总比本地快多少 */

科学的依赖缓存方案

1. 推荐缓存“store”,而非 node_modules

  • Yarn v1: ~/.cache/yarn
  • pnpm: .pnpm-store 或 ~/.pnpm-store
  • npm: ~/.npm
  • 只要 store 命中,包管理器能极快增量恢复依赖,把 node_modules 重建成本降到最低,还能利用 cache 最大化加速。

2. 更优体验与维护

  • store 缓存具备良好的增量性,依赖变动时只需下载新增部分。
  • 配合 lockfile 做 cache key,保障构建环境一致性,最大化利用 cache。
  • node_modules 每次 clean install,消除残留幽灵依赖的风险。

总结

node_modules cache 并非最佳实践,依赖一变就失效、维护负担大、提速有限。推荐用包管理器自带的 store 缓存方案,实现安全、高效、一致的 CI/CD 依赖管理。

让缓存提速真正简单可控,让构建和调试更加安心。如果你还在纠结 node_modules cache,不如现在就切换到 store 缓存吧!