跳到主要内容

为什么项目应该只用 pnpm

· 阅读需 4 分钟
ZhiQing Lin
CEO | Fuzhou Beisi Network Technology Co., Ltd.

一个项目到底用 npm、yarn 还是 pnpm,看起来只是命令不同。真正做过几次依赖升级、多人协作和持续集成之后,会发现这其实是一个工程约束问题。

我的判断是:项目既然选择了 pnpm,就不应该继续允许 npm 被使用。

混用包管理器,问题不只是一份锁文件​

很多项目会出现这样的情况:有人执行 npm install,有人执行 pnpm install,CI 又使用另一套命令。只要项目暂时还能启动,大家就觉得问题不大。

但依赖安装并不是一个完全没有副作用的过程。不同包管理器对依赖树、peer dependency、lockfile 和 node_modules 的处理方式并不完全一样。一次看似普通的安装,可能让锁文件发生变化,也可能让本地能运行的结果和 CI 不一样。

这类问题通常不会立刻暴露。它们更像是被埋在项目里的不确定性:今天没有报错,不代表下次升级依赖时还会一样。

所以,项目真正需要的不是“大家都知道几种包管理器”,而是同一个项目只有一条确定的依赖安装路径。

为什么选择 pnpm​

选择 pnpm,最直接的原因是它更适合长期维护的项目。

首先,pnpm 使用内容寻址存储,同一台机器上的多个项目可以复用相同的依赖文件。相比每个项目都完整复制一份依赖,它通常能减少磁盘占用,也能让重复安装更快。

其次,pnpm 的依赖目录结构更严格。项目只能访问自己声明的依赖,不能因为某个间接依赖碰巧出现在扁平化目录里,就直接在代码中使用它。这个限制会让一些隐藏依赖更早暴露出来,反而有利于维护。

当然,pnpm 不是所有场景下的唯一答案。一个老项目如果已经稳定使用 npm,没有必要为了追求工具统一而强行迁移。真正重要的是选定之后持续使用,而不是在工具之间来回切换。

为什么要禁止 npm​

如果只在文档里写一句“推荐使用 pnpm”,实际效果通常不够。

“推荐”意味着还有另一条路。新成员可能照着旧文章执行 npm install,自动化脚本可能继续运行 npm ci,某个临时排查问题的人也可能顺手执行 npm run build。这些操作单独看都很合理,但最后会让项目失去唯一的标准。

禁止 npm 的重点,不是认为 npm 这个工具不好,而是不要让同一个项目同时维护两套工作方式。

当项目明确只使用 pnpm 时,安装依赖、执行脚本、更新锁文件和 CI 构建,都应该使用同一套命令。这样出了问题,排查范围会更小,团队也不会争论“到底应该用哪条命令”。

禁止的是 npm 命令,不是 npm registry​

这里还需要区分一个容易混淆的地方。

npm 既可以指 npm 包管理器,也常被用来指 npm registry。项目禁止使用 npm install,不等于必须禁止从 npm registry 下载依赖。pnpm 默认仍然可以从 npm registry 获取公开包,这两件事并不矛盾。

真正要禁止的是这些项目操作:

  • 用 npm install 安装或更新依赖;
  • 用 npm ci 作为 CI 的安装方式;
  • 用 npm run 执行项目脚本;
  • 提交或继续维护与项目包管理器不一致的 lockfile。

项目可以使用 pnpm install、pnpm add、pnpm run build,并让 CI 使用完全相同的安装和构建方式。

统一工具,减少无意义的选择​

开发工具的选择本身不是目的。真正有价值的是把不需要讨论的事情固定下来。

依赖应该怎么装、锁文件由谁生成、CI 用什么安装、脚本用什么执行,这些如果每个人都可以自由选择,项目就会把时间花在工具差异上。统一使用 pnpm,并明确禁止 npm,本质上是在减少一类没有收益的自由度。

对一个需要长期维护的项目来说,少一条隐含路径,就少一种环境差异。不是因为 pnpm 永远正确,而是因为同一个项目不应该同时拥有两套标准。