概述
目前在前端领域最流行的包管理工具包含了 npm、yarn、pnpm,其中 pnpm 的优势越来越越明显,它通过软硬链接依赖的方式实现了快速安装,当下各种类库、组件库的最佳实践方案也基本都是 pnpm + monorepo。
包管理工具发展史
npm 的诞生
随着 Node.js 的推出,开发者需要一种管理众多 JavaScript 库和模块的方法,npm(Node Package Manager)由此诞生。
npm 于2010年被引入,很快成为 Node.js 生态系统中分享和管理模块的标准方式。其中 node_modules 目录就是npm用来局部安装依赖的地方,使得不同的项目可以使用不同版本的包,而不会互相干扰。随着时间的推移,npm 还成为了一个庞大的开源库生态系统,目前已是世界上最大的软件注册机构。
然而,随着 npm 的快速成长,一些问题也随之而来,比如 node_modules 随着依赖的嵌套,体积越来越大。
npm 的嵌套依赖模型
在 npm2 及以前,每个包会将其依赖安装在自己的 node_modules 目录下,这意味着每个依赖也会带上自己的依赖,形成一个嵌套的结构,结构如下:
这样的结构虽然解决了版本冲突、依赖隔离等问题,但却有几个致命的缺点:
- 磁盘空间占用:每个依赖都会安装自己的依赖,导致了大量的重复,特别是在多个包共享同一依赖的场景下。
- 深层嵌套问题 :这种嵌套结构在文件系统中造成了非常长的路径,然而大多数 Windows 工具、实用程序和 shell 最多只能处理长达 260 个字符的文件和文件夹路径。一旦超过,安装脚本就会开始出错,而且无法再使用常规方法删除 node_modules 文件夹。相关 issue:github.com/nodejs/node...
- 安装和更新缓慢:每次安装或更新依赖时,npm 需要处理和解析整个依赖树,过程非常缓慢。
npm3 升级
npm3解决了上述痛点
通过将依赖扁平化,尽可能地减少了重复的包版本,有效减少了项目的总体积 ,同时也避免了 npm 早期的深层嵌套问题。
扁平化结构如下:
可以看到还是会有一定可能产生嵌套问题,因为根目录只能存放某个包的一个版本。
yarn 的出现
yarn 的出现是为了解决 npm 当时存在的一些问题,旨在提供一个更快、更安全的 JavaScript 包管理工具。
yarn 的特点:
- 性能提升:yarn 在发布之初就强调了性能优势,特别是在安装依赖时。它通过并行安装依赖和缓存已下载的包来加速这一过程,减少了安装时间。
- 更好的依赖管理:yarn 引入了 yarn.lock 文件,这个锁文件确保了依赖的一致性。无论是在哪个环境下运行yarn install,都能确保安装相同版本的依赖,解决了因版本不匹配导致的问题。
- 更好的安全性:yarn 通过检查安装的每个包的许可证,并提供了一种机制来限制或拒绝具有不安全许可证的包的安装,增强了项目的安全性。
仍然存在的问题
其实扁平化的结构还是存在一些问题的,那就是幽灵依赖。
我们假设 B 并没有在 package.json 中注册,但由于 A 依赖 B,B会被提取到 node_moduls 顶层,那么在项目中就可以直接引用 B,这就是幽灵依赖,当 A 出现一些变动时(升级、删除),会导致出现几个问题:
- 环境不一致:由于该模块未在 package.json 文件中声明,当在其他环境(如测试、生产环境或者其他人的开发环境)中部署应用时将无法知道需要包含那些模块。这将导致环境之间存在不一致,可能会导致在其他环境中运行时出现错误。
- 版本控制问题:由于未明确声明依赖,可能会出现不同环境中使用的模块版本不一致的问题。这可能导致某些功能在某些环境中无法正常工作,或者出现不可预见的行为。
- 代码可读性和可维护性降低:开发人员无法清楚地了解应用程序的依赖项,导致代码理解困难。
而 pnpm 就是为了解决这个问题而出现的。
pnpm 横空出世
pnpm旨在解决 npm 和 yarn 在某些方面存在的效率和存储问题,同时通过引入一种独特的链接方式有效地解决了大部分幽灵依赖的问题。
硬链接和软链接(符号链接)
在了解 pnpm 之前,我们先了解一下硬链接和软链接的概念:
硬链接
概念
硬链接是文件系统中的一个链接,它指向磁盘上的数据。当创建一个硬链接时,实际上是在创建一个和原始文件相同的入口点,但是不占用额外的磁盘空间。这个新的链接和原始文件共享相同的数据块,任何一个文件的修改都会反映在另一个上。
- 特点:硬链接不能跨文件系统创建,也不能用于链接目录,但如果原始文件被删除,硬链接依然可以访问数据。
- 使用场景:当你想要在不同位置访问同一个文件内容,而又不想占用额外磁盘空间时,可以使用硬链接。比如,在多个项目中共享相同的库文件,但不需要复制这个文件多份。
软链接
概念
软链接是一个特殊类型的文件,它包含了另一个文件的路径。类似于 Windows 系统中的快捷方式。与硬链接不同,软链接可以指向目录,也可以跨文件系统。
- 特点:软链接指向文件或目录的路径,如果原始文件被删除,软链接就会失效,因为它的指向已经不存在了。
- 使用场景:软链接适用于需要引用特定位置的文件或目录时,特别是当这些文件或目录可能会移动或变化时。它允许链接到另一个文件系统中的文件或目录。
pnpm 中的硬软链接应用
硬链接
pnpm 通过使用全局的 .pnpm-store 来存储下载的包,使用硬链接来重用存储在全局存储中的包文件,这样不同项目中相同的包无需重复下载,节约磁盘空间。
软链接
pnpm 将各类包的不同版本平铺在 node_modules/.pnpm 下,对于那些需要构建的包,它使用符号链接连接到存储在项目中的实际位置。这种方式使得包的安装非常快速,并且节约磁盘空间。
pnpm的优点
- 节省磁盘空间:由于使用硬链接,相同的包不需要被重复存储,大大减少了磁盘空间的需求。
- 提高安装速度:安装包时,pnpm 通过创建链接而非复制文件,这使得安装过程非常快速。
- 确保依赖隔离:通过软链接有效减少了幽灵依赖产生的可能,同时保证了依赖的隔离。