pnpm 是什么?它真的这么快而且节省空间吗?
我们在 ViteConf 上宣布,我们的WebContainers 现已支持 pnpm。这标志着我们兑现了支持 Vite 生态系统的承诺,这是一项重大成就,因为许多在 Vite 上运行的项目也使用 pnpm(例如 Vue、Astro 和 SvelteKit)。
在这篇文章中,我想谈谈pnpm 与其他包管理器的区别,以及我们为什么需要包管理器。作为一个擅长类比的人,我还将讨论:🍣 寿司、🪦 墓地、🎁 生日和🖼 表情包。
什么是包管理器?
让我们从术语开始。
包、依赖项、节点模块
“包”(或“依赖项”)是指一个或几个整齐捆绑在一起的文件,可以从包仓库下载。下载并安装后,它会驻留在node_modules
项目目录中的文件夹中。在本文中,我将像许多技术社区的同仁一样,交替使用 Node 模块、包和依赖项这几个词。话虽如此,npm 文档对此有不同的看法,所以如果您对细节和准确性感兴趣,可以去看看。🙂
包.json
每个包都有一个名为 的文件package.json
,其中包含包的作者、版本、依赖项等信息。一个包可以包含多个依赖项,而这些依赖项又可以包含多个依赖项(称为“子依赖项”)。这听起来文件很多,不是吗?确实如此,尤其是在您的项目需要更大的包时。
在过去,您需要手动下载、安装和配置应用程序的依赖项。请记住,大多数软件包都会频繁更新,这意味着您必须始终确保项目的依赖项(以及它们的子依赖项!)是最新的,或者在给定项目中使用给定软件包的正确版本。这听起来不仅压力很大,而且还会造成不必要的重复!这时,包管理器就派上用场了。
包管理器
软件包管理器是一款帮助您以一致的方式跟踪应用所有依赖项的工具。它可以自动执行依赖项的安装、升级、配置和移除任务。它确保应用所需的所有软件包都已安装,且版本正确且保持最新。这为您节省了大量的编码时间……以及避免拖延的时间🤪
第一个 Node 运行时包管理器 npm 直到 2010 年才推出(与普遍的看法相反,它并非“Node 包管理器”的缩写,实际上只是一个空洞的缩写)。十二年后,npm 现在由微软管理,此外还有两个竞争者在争夺包管理领域的王座:yarn 和 pnpm。
包管理器做什么?
软件包管理器从在线注册表中抓取已发布的源文件,并将它们安装到名为 的目录(文件夹)中node_modules
。当你调用该方法时,你的应用将在此文件夹中查找软件包require()
。
你可以把文件夹想象node_modules
成一个盒子,里面装着各种实用工具,可以插入到你的应用中,让它以你想要的方式运行。只不过,所有工具都是铁(或者锇!)做的,而且盒子很大。我的意思是,遗憾的是,在 pnpm 出现之前,node_modules
文件夹通常很笨重,占用大量磁盘空间。这导致了一系列 meme 的出现,例如:
想象一下,你的本地机器上有很多项目,每个项目都有自己的 node_modules 文件夹。很可能很多项目都使用类似的技术栈。在这种情况下,你最终会在很多项目中使用相同的包。重复和冗余!想想那些从未离开样板阶段的、充满灵感的业余项目,想想过去尝试各种热门新框架的尝试——所有这些都占用着你宝贵的磁盘空间。
谁诅咒了node_modules
文件夹?
为了理解这些笑话,我们需要回顾一下过去,看看传统上如何处理包管理。
npm 尽其所能地处理依赖关系,将安装(例如,由 触发npm install
)过程分为三个阶段:
- 解析:当包管理器检查文件中列出的所有项目依赖项(及其子依赖项)时
package.json
,它会找到一个满足版本说明符的版本(例如,^1.0.0
安装任何未来的次要版本/补丁版本)。之后,它会创建一个类似于package-lock.json
npm 和pnpm-lock.yaml
pnpm 的文件。你可以把它想象成一个项目的生日礼物愿望清单。 - 获取,当包管理器获取已解析的依赖项列表并从包注册表中获取所有包时,这相当于在聚会前两个小时在拥挤的商场里疯狂购物,为所有朋友赠送给生日人的礼物。
- 链接,当包管理器将所有依赖项写入项目
node_modules
文件夹时,这最终相当于将所有礼物放在派对房间的角落以备需要时使用。
在这种情况下,每个阶段都需要结束才能开始下一个阶段。这意味着,如果一个依赖项本身有二十个依赖项,或者一个包需要很长时间才能下载,你可能需要等待很长时间。如果我们按照生日的比喻,想象一下愿望清单中包含一款流行手机的新版本和一盒巧克力。你最终要在手机商店门前排几天队才买到巧克力。在这样的系统中,你无法“保留”你在队列中的位置,去买巧克力然后参加派对,即使这看起来更能有效地利用你的时间。你会发现npm 管理任务的方式效率不高。 *
正如我们之前所说,这也与磁盘空间有关。最终你会得到大量相同软件包的重复文件。即使同一个软件包有不同版本,也很少会出现所有文件都从一个版本更改为另一个版本的情况。你最终仍然会得到一些副本。我们同意npm 管理磁盘空间的方式效率不高。
pnpm 如何解决我们所有的担忧和烦恼?
在其文档页面上,您可以看到 pnpm 是一款“快速、节省磁盘空间的包管理器”。它确实很快——本地速度比其他方案快三倍——而且节省空间。但是——它是如何做到的呢?
pnpm 很快
你还记得生日愿望清单的比喻吗?npm 就像一个跑腿的,它首先收集了所有的愿望,然后买了所有的礼物,最后把它们摆放在派对房间的角落里。每个阶段都需要结束才能开始下一个阶段。这就是 npm 跑腿的生命周期安排方式。
好吧,如果 pnpm 是跑腿的,他们会在读到愿望后立即购买礼物,并在下单后立即指定房间的位置。他们甚至可能还没有收到实体礼物,就无法在房间里标记好放置礼物的位置。每个礼物的安装过程都是独立且相互独立的。pnpm 的设计使其没有安装过程中的阻塞阶段——每个软件包的安装过程都是独立运行的。
pnpm 节省磁盘空间
说说吃的吧。我超爱素食寿司,点了很多素食寿司。我也吃很多芥末,而且我不喜欢浪费。虽然可以合理地假设这么多份量肯定要大家一起分享,但我通常只点一份给自己吃。我的订单总是会附赠两双筷子,尽管我在电话里说我不需要——我家里有金属筷子。我不会把不用的筷子扔掉,现在我抽屉里装满了,你甚至会在厨房里最意想不到的地方看到它们。同样,我有自己的芥末筒,但我会扔掉那些小袋装的芥末吗?永远不会。它们在我的冰箱里冷藏,而且越来越大。
我的筷子和芥末可以用来比喻 npm 如何管理磁盘空间。“哦,你已经安装了两百次 React 了?我肯定你需要第 201 次!”
让我欣慰的是,pnpm 会检查磁盘上已有的内容,并仅添加项目运行所需的额外内容。所有依赖项都位于一个全局位置(例如,~/.pnpm-store/
您可以在终端中运行来检查pnpm store path
),称为“内容可寻址存储”。项目文件node_modules
夹中有一个.pnpm
文件,其中包含“虚拟存储”,其中包含许多所谓的“硬链接”。它会为每个包的每个文件创建一个硬链接。我喜欢 pnpm 文档提供的以下解释:
例如,如果您
foo
的项目中有一个依赖项,它占用了 1MB 的空间,那么它看起来在项目node_modules
文件夹中占用了 1MB 的空间,在全局存储中也占用了相同大小的空间。然而,这 1MB 是磁盘上从两个不同位置寻址的相同空间。因此,它总共foo
占用 1MB,而不是 2MB。
这使得node_modules
文件夹更像是一个门户(就像纳尼亚的衣橱),可以访问位于全局存储不同角落的文件,而不是一个臃肿的存储单元。下图展示了 pnpm 采用的策略:
但是,pnpm 是否“知道”同一软件包的两个版本之间是否存在重复文件?是的,因为就像 git 一样,它通过哈希 ID(也称为“内容完整性”或“校验和”)而不是文件名来标识文件。这意味着两个相同的文件将具有相同的哈希 ID,pnpm 将确定没有重复的理由。
pnpm 为您提供支持
pnpm 为您提供了诸多帮助。其中之一就是,您不可能因为尝试使用项目中未直接指定但项目依赖项所需的模块而 引发愚蠢的错误package.json
。如果一切运行正常,这并非世界末日,但如果项目的依赖项不再需要某个软件包,导致该软件包在文件node_modules
夹中不再可用,会发生什么情况?那么,一切都会崩溃,而您甚至不知道原因。
此类错误可能出现在 npm 和 Yarn Classic 中,因为其采用扁平node_modules
目录结构,在安装过程中,它们会将所有包提升到 目录node_modules
,无论这些包是否被你的应用直接依赖。结果,你的项目可以访问其依赖项的远亲。
...但是如果我的项目不支持符号链接怎么办?
即使你的项目存在特殊情况,无法很好地使用符号链接,也不用担心!你仍然可以使用 pnpm,但需要将其设置为类似 npm 的模式。虽然这样空间利用率会有所降低,但速度仍然会更快。
但是...Yarn 怎么样?
Yarn 有两个版本:
- “Yarn Classic” 包含 v2 以下版本,并且不再维护,
- “ Yarn Berry ”,版本 2 及更高版本。
Yarn Classic 在管理文件夹方面与 npm 类似node_modules
。而 Yarn Berry 则提供了三种解决方案:
- 类似 npm 模式
- “即插即用”模式
- 类似 pnpm 的模式,使用硬链接来减少磁盘空间(默认情况下不可用且没有详细记录)
即插即用似乎是一个有趣的选择,但它引起了社区的担忧,因为.zip
在开发工作流程中文件不太容易访问。TakeShape 之前提到的帖子解释了其他一些挑战。
结束语
考虑到 pnpm 节省空间且速度极快,越来越多的项目选择它,并且它的受欢迎程度迅速增长也就不足为奇了。今年,pnpm 的每周下载量是去年的七倍!
如果您有兴趣了解项目选择切换到 pnpm 的原因,请查看Gestalt和TakeShape的这些帖子。
进一步阅读
以下进一步的阅读材料可能会帮助您更好地了解包管理器的当前状况:
来和我们一起开发包管理器吧!
趁你还在等什么,先发布一条公告:我们正在寻找一位新团队成员,负责开发包管理器,包括 pnpm、npm、yarn 以及我们自己的Turbo。感兴趣吗?立即申请或在 Twitter 上联系我!
文章来源:https://dev.to/stackblitz/what-is-pnpm-and-is-it-really-so-fast-and-space-efficient-29la