从 npm 到 pnpm:为什么新的包管理器更受欢迎

更新日期: 2025-11-14 阅读: 41 标签: pnpm

前端和 Node.js 开发中,包管理器是我们每天都要用的工具。它帮助我们管理项目需要的各种代码库。从最早的 npm,到后来的 yarn,再到现在越来越多人使用的 pnpm,每次变化都是为了解决三个问题:安装速度、磁盘空间、依赖关系的一致性。


npm 面临的问题

npm 是 Node.js 的官方包管理器,为整个生态奠定了基础。但随着项目越来越大,它的设计缺陷也逐渐暴露出来。

磁盘空间浪费严重

npm 处理依赖包的方式比较低效。在早期版本中,依赖包是嵌套安装的。这意味着如果两个包都依赖同一个库,这个库会被安装两次。

比如,包 A 需要 lodash@4.17.0,包 B 也需要 lodash@4.17.0,那么你的 node_modules 里就会有两份完全相同的 lodash。

即使在新版本中引入了扁平化结构,不同版本的相同包仍然会被重复安装。如果包 A 需要 lodash@4.17.0,包 B 需要 lodash@4.18.0,两个版本都会保留在项目中。

对于需要维护多个项目的开发者来说,这种重复存储会浪费大量磁盘空间。比如你有 10 个项目都用到了 react@18.0.0,npm 会在每个项目里都保存一份 react,总共就是 10 份相同的代码。

安装速度慢

npm 安装包的过程比较繁琐:先下载,再解压,然后复制到 node_modules。由于相同的包需要重复下载和复制,大量的磁盘读写操作拖慢了安装速度。

举个例子,第一次安装 react 需要下载 100KB 数据。当你创建新项目再次安装 react 时,npm 又会重新下载并复制这些数据,无法利用之前已经下载的内容。

依赖关系不可靠

npm 还有两个常见问题:幽灵依赖和版本冲突。

幽灵依赖指的是,你的项目能用到的某些包,并没有在 package.json 中声明。这是因为 npm 会把一些间接依赖提升到 node_modules 根目录。比如包 A 依赖包 B,包 B 依赖包 C,包 C 会被提升到根目录,导致你的代码可以直接引用包 C。如果以后包 B 不再依赖包 C,你的项目就会突然报错。

版本冲突发生在多个包依赖同一个包的不同版本时。虽然 npm 会尝试处理这种情况,但复杂的依赖关系仍然可能导致问题,出现"在我电脑上能运行,在别人电脑上就报错"的情况。


pnpm 的解决方案

pnpm 通过创新的链接机制,同时解决了空间、速度和一致性问题。要理解 pnpm 的工作原理,我们需要先了解两个操作系统概念:硬链接和符号链接。

理解硬链接和符号链接

在操作系统中,文件实际上是指向磁盘内容的指针,而不是内容本身。当你删除文件时,删除的只是指针,磁盘上的内容还在,直到被新数据覆盖。

硬链接相当于给同一个文件内容创建多个入口。多个文件名指向相同的磁盘内容。修改任何一个硬链接文件,其他链接的文件也会同步修改。删除原文件,只要还有硬链接存在,文件内容就不会被真正删除。

硬链接的特点是:

  • 不占用额外磁盘空间

  • 只能用于文件,不能用于目录

  • 删除原文件不影响其他硬链接

符号链接(也叫软链接)类似于快捷方式,它记录的是目标文件的路径。当你访问符号链接时,系统会自动跳转到实际的文件位置。

符号链接的特点是:

  • 占用空间很小(只存储路径信息)

  • 可以链接文件和目录

  • 如果原文件被删除,符号链接就会失效

pnpm 的工作机制

pnpm 的核心思路是:使用全局缓存配合硬链接和符号链接,构建一个没有重复依赖、可以复用、保证一致性的依赖管理方案。

我们通过一个具体例子来说明。假设项目 proj 依赖包 a,包 a 又依赖包 b。

第一步:分析依赖关系

pnpm 首先读取 package.json,分析出需要安装包 a。然后读取包 a 的 package.json,发现它依赖包 b。最终确定需要安装 a 和 b。

这一步和 npm 的做法是一样的。

第二步:检查全局缓存

pnpm 维护一个全局缓存目录(在 Windows 上通常是 C:\Users\用户名\AppData\Local\pnpm\store)。所有下载过的包都会在这里保存一份。

如果 a 和 b 已经在缓存中,就直接使用。如果不在,就从 npm 仓库下载并保存到缓存。

这样,不管有多少个项目需要同一个包,都只需要下载一次。

第三步:创建项目依赖结构

pnpm 在项目的 node_modules 里创建 .pnpm 目录,这里存放所有的硬链接。

从全局缓存为 a 和 b 创建硬链接,放到 .pnpm 目录:

node_modules/.pnpm/a@1.0.0/   # 指向全局缓存的硬链接
node_modules/.pnpm/b@2.0.0/   # 指向全局缓存的硬链接

这些硬链接不占用额外空间,因为它们和缓存指向相同的磁盘内容。

第四步:建立包之间的依赖关系

包 a 需要能访问到包 b。pnpm 在包 a 的目录下创建 node_modules,里面用符号链接指向包 b:

node_modules/.pnpm/a@1.0.0/node_modules/b -> ../../b@2.0.0

当包 a 的代码执行 require('b') 时,会通过这个符号链接找到真正的包 b。

第五步:让项目能访问直接依赖

项目需要能直接使用包 a。pnpm 在项目根目录的 node_modules 里创建指向包 a 的符号链接:

node_modules/a -> .pnpm/a@1.0.0

这样,项目代码就可以正常导入包 a 了。

最终的项目结构如下:

proj/
└─ node_modules/
   ├─ a -> .pnpm/a@1.0.0        # 项目直接访问的符号链接
   └─ .pnpm/
      ├─ a@1.0.0/               # 包a的硬链接
      │  └─ node_modules/
      │     └─ b -> ../../b@2.0.0  # 包a依赖包b的符号链接
      └─ b@2.0.0/               # 包b的硬链接


pnpm 的优势

大幅节省磁盘空间

所有项目共享同一份全局缓存,相同版本的包只存储一次。10 个项目使用相同的 react 版本,磁盘占用减少 80% 以上。

安装速度更快

首次安装后,后续安装相同依赖时无需下载,只需创建链接。根据测试,pnpm 的安装速度比 npm 快 2-3 倍。

依赖关系更可靠

间接依赖不会被提升到根目录,彻底杜绝幽灵依赖。所有依赖版本通过硬链接锁定,确保一致性。


实际使用对比

让我们看看在实际项目中,pnpm 和 npm 的差异。

创建新项目:

# 使用 npm
npm create react-app my-app
# 需要下载 200MB+ 依赖

# 使用 pnpm  
pnpm create react-app my-app
# 如果之前下载过相关依赖,只需几秒钟

安装现有项目:

# 使用 npm
npm install
# 需要下载所有依赖

# 使用 pnpm
pnpm install
# 大部分依赖从缓存链接,速度很快

磁盘空间对比:
假设有 5 个 React 项目:

  • npm:每个项目 node_modules 约 200MB,总共 1GB

  • pnpm:全局缓存约 200MB,每个项目 node_modules 主要是链接,总共约 300MB


迁移到 pnpm

从 npm 迁移到 pnpm 很简单:

  1. 删除现有的 node_modules 目录

  2. 删除 package-lock.json 文件

  3. 运行 pnpm install

pnpm 会使用与 npm 相同的 package.json,所以不需要修改依赖声明。


适用场景

推荐使用 pnpm 的情况:

  • 需要维护多个项目

  • 磁盘空间有限

  • 追求更快的安装速度

  • 需要严格的依赖管理

npm 仍然可用的场景:

  • 简单的个人项目

  • 对现有工作流很满意

  • 使用的某些工具与 pnpm 不兼容


总结

从 npm 到 pnpm 的转变,体现了包管理器从"复制依赖"到"链接依赖"的进化。pnpm 没有改变 npm 的生态系统,而是用更聪明的方式解决了长期存在的问题。

对于开发者来说,使用 pnpm 几乎没有任何学习成本(用 pnpm install 代替 npm install),但能获得更好的体验。这就是为什么越来越多的开源项目和大公司开始转向 pnpm。

好的工具不一定要颠覆现有生态,而是找到更优雅的解决方案。pnpm 正是这样的例子,它用创新的思路解决了前端开发中的实际问题。

本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/article/detial/13175

简单带大家实践一下pnpm,也就几分钟的事情~

说pnpm之前先说说Monorepo,它是一个思想,我举个例子,我现在需要做一个大项目——电商平台,那么我需要做以下几个子项目:电商Web端、电商H5端

从 npm 切换到 pnpm

pnpm 是新一代包管理工具,为什么叫 pnpm 呢,是因为 pnpm 作者对现有的包管理工具,尤其是 npm 和 yarn 的性能特别失望,所以起名叫做 performance npm,即 pnpm(高性能 npm)

该用 pnpm 了,“快、准、狠”。

pnpm 全称是 “Performant NPM”,即高性能的 npm。它结合软硬链接与新的依赖组织方式,大大提升了包管理的效率,也同时解决了 “幻影依赖” 的问题,让包管理更加规范

npm,pnpm,yarn,npx的那些事儿

最早发布的包管理器是 npm,他在 2010 年 1 月就已经发布了。它确立了包管理器工作的核心原则。npm 的发布诞生了一场革命,在此之前,项目依赖项都是手动下载和管理的。

为什么越来越多的公司要求使用 pnpm?

如果你最近加入一家新的技术团队,可能会发现他们强制要求使用一个叫做 pnpm 的工具来管理项目依赖,而不是我们熟悉的 npm 或 Yarn。这并非跟风,而是为了解决前端开发中长期存在的一些痛点。

选择合适的包管理器:npm、Yarn 和 pnpm 的比较

在前端开发中,包管理器是必不可少的工具。从最早的 npm 到后来的 Yarn,再到现在流行的 pnpm,每个工具都在前一个基础上做出了改进。理解这些工具的特点,能帮助我们在不同场景下做出合适的选择,提升开发效率。

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!