为什么我们应该使用 pnpm(译)

2018-02-09 12:41:47来源:https://segmentfault.com/a/1190000013214927作者:SegmentFault人点击

分享


pnpm
是又一个 Node.js 包管理工具。它可以替换 npm, 而且 npm 更快更高效。



能有多快?3 倍!
可以在这里
查看 benchmarks 。


为什么更高效? 当你安装一个软件包,我们把它保存在你的机器上的一个全局存储目录中,然后我们创建一个硬链接而不是复制。 对于模块的每个版本,只会有一个副本保存在磁盘上。 例如,当使用 npm 或 yarn 时,如果有 100 个使用 lodash 的项目,你的磁盘上就会有有 100 份 lodash 的拷贝。pnpm 能帮助您节省千兆字节的磁盘空间!


为什么不用
Yarn


老实说,当Yarn
开始公开时,我真的很失望。 几个月来我一直在为pnpm
作出重大贡献,而且没有任何关于 Yarn 的消息。 有关其发展的信息是不公开的。


几天之后,我意识到 Yarn 只是 npm 的一个小小的改进。 尽管它使得安装速度更快,并且具有一些不错的新功能,但是它使用了与 npm 相同的扁平 node_modules 结构(从版本 3 开始)。


扁平化的依赖关系树带来了一系列的问题:


模块可以访问他们不依赖的软件包
扁平化依赖树的算法相当复杂
一些软件包必须复制在一个项目的 node_modules 文件夹中

此外,还有一些 Yarn 不打算解决的问题,如磁盘空间使用问题。 所以我决定继续把时间花在 pnpm 上,并取得了巨大的成功。 截至目前(2017 年 3 月),pnpm 具有 Yarn 超过 npm 的所有附加功能:


安全
。 像 Yarn 一样,pnpm 有一个特殊的文件,其中包含所有安装包的校验码,以在代码执行之前验证每个已安装包的完整性。
离线模式
。 pnpm 将所有下载的软件包 tar 包保存在本地镜像仓库中。 当一个包在本地可用时,它从不发出请求。 使用 --offline 参数,HTTP 请求可以被完全禁止。
速度
。 pnpm 不仅比 npm 快,而且比 Yarn 还要快。 它比 cold 和 hot 缓存 Yarn 都快。 Yarn 从缓存拷贝文件,而 pnpm 只是从全局存储目录链接它们。
这怎么可能?

正如我前面提到的,pnpm 不会拍平依赖关系树。 因此,pnpm 使用的算法可以更容易! 这就是为什么只有一名开发人员能够跟上 Yarn 的几十位贡献者的步伐。


那么,如果不依靠拍平的方式,pnpm 如何构造 node_modules 目录呢? 为了理解它,我们应该回忆在 npm 版本 3 之前 node_modules 文件夹看起来是怎样的。在 npm@3 之前,node_modules 结构是可预测和干净的,因为 node_modules 中的每个依赖项都有自己的 node_modules 以及所包含依赖关系的 package.json 文件。


node_modules
└─ foo
├─ index.js
├─ package.json
└─ node_modules
└─ bar
├─ index.js
└─ package.json

这种方法有两个严重的问题:


频繁使用的代码包创建了太深的依赖关系树,导致 Windows 上很长的目录路径问题
当被不同的依赖关系需要时,代码包会被复制粘贴多次

为了解决这些问题,npm 重新思考了 node_modules 结构,并提出了扁平化。 在 npm@3 中,node_modules 的结构现在看起来像这样:


node_modules
├─ foo
|├─ index.js
|└─ package.json
└─ bar
├─ index.js
└─ package.json


有关 npm v3 依赖关系解析的更多信息,请参见npm v3 依赖关系解析


与 npm@3 不同,pnpm 试图解决 npm@2 所具有的问题,而不是将依赖关系树展平。 在由 pnpm 创建的 node_modules 文件夹中,所有的软件包都有自己的依赖关系,但是目录树永远不会像 npm@2 那么深。 pnpm 保持所有依赖关系平坦,但使用符号链接将它们组合在一起。


-> - a symlink (or junction on Windows)
node_modules
├─ foo -> .registry.npmjs.org/foo/1.0.0/node_modules/foo
└─ .registry.npmjs.org
├─ foo/1.0.0/node_modules
|├─ bar -> ../../bar/2.0.0/node_modules/bar
|└─ foo
| ├─ index.js
| └─ package.json
└─ bar/2.0.0/node_modules
└─ bar
├─ index.js
└─ package.json


要查看实例,请访问示例 pnpm 项目


虽然这个例子对于一个小项目似乎太复杂了,但是对于更大的项目来说,结构看起来比 npm / yarn 创建的结构要好。 让我们看看为什么它不错。



首先,您可能已经注意到,node_modules 根目录下的包只是一个符号链接。 这很好,因为 Node.js 忽略符号链接并执行实际路径。 所以 require('foo')会执行文件node_modules/.registry.npmjs.org/foo/1.0.0/node_modules/foo/index.js
而不是node_modules/foo/index.js



其次,没有一个安装的软件包在其目录中有自己的 node_modules 文件夹。 那么foo
怎么引入bar
? 让我们看看包含foo
包的文件夹:


node_modules/.registry.npmjs.org/foo/1.0.0/node_modules
├─ bar -> ../../bar/2.0.0/node_modules/bar
└─ foo
├─ index.js
└─ package.json

如您所看到的


foo
的依赖关系(只有bar
)被安装,但在目录结构中的一级。
这两个软件包都位于名为 node_modules 的文件夹内。


foo
可以引入bar
,因为 Node.js 在目录结构中查找模块直到磁盘的根目录。 而且foo
也可以引入foo
,因为它在一个名为 node_modules 的文件夹中(没错,这正是一些软件包所做的)。


你相信吗?

只需通过 npm 安装 pnpm:npm install -g pnpm。 只要你想安装一些东西,就用它来代替 npm:pnpm i foo。



您也可以在pnpm GitHub repo
或pnpm.js.org
中阅读更多信息。 您可以关注pnpm on Twitter
,或者在pnpm Gitter Chat Room
寻求帮助。



原文:Why should we use pnpm?


最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台