likes
comments
collection
share

pnpm对比 npm/yarn好在哪里

作者站长头像
站长
· 阅读数 13

deadline是第一生产线,在本Q的最后一天,在团队小伙伴们都有或多或少的文章产出的压力之下,终于我也难产出这一篇文章。

要想了解 pnpm 的优势在哪里,知道它解决了什么问题,就要知道 pnpm 的作者在开发 pnpm 的时候,他认为的 npm/yarn 的弱点在哪里。

npm/yarn扁平化的安装机制

npm install安装是在确定了包的版本后,获取包信息,构建依赖树然后进行扁平化处理,将所有依赖包安装在同一层级。

扁平化后的node_modules目录如下:

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

在使用依赖包的过程中,所有依赖都在同一层级去找,解决了npm@3之前的版本以下问题:

  • 将所有依赖包安装成树结构之后,大量重复的安装了依赖,造成安装速度非常慢,磁盘空间管理非常差
  • 依赖的层级太深导致文件路径过长

但是依赖扁平化后,就会出现下列问题:

  1. 模块可以访问没有声明依赖的包
  2. 扁平化一个依赖树的算法非常复杂(耗时)
  3. 在项目的中有一些包被重复安装

第一个问题在前司遇到过,有时在一个项目中,并没有声明对某个包的依赖,但是却可以使用,而在其他包的依赖中升级了或者移除这个依赖包时,就会出现错误。

问题3我没有理解,在下面这篇文章中找到了答案👇

讲解如下:

假如现在项目依赖两个包 foo 和 bar,这两个包的依赖又是这样的: pnpm对比 npm/yarn好在哪里

那么 npm/yarn install 的时候,通过扁平化处理之后,究竟是这样 pnpm对比 npm/yarn好在哪里

还是这样?

pnpm对比 npm/yarn好在哪里

答案是: 都有可能。取决于 foo 和 bar 在 package.json中的位置,如果 foo 声明在前面,那么就是前面的结构,否则是后面的结构。

这就是为什么会产生依赖结构的不确定问题,也是 lock 文件诞生的原因,无论是package-lock.json(npm 5.x才出现)还是yarn.lock,都是为了保证 install 之后都产生确定的node_modules结构。

尽管如此,npm/yarn 本身还是存在扁平化算法复杂package 非法访问的问题,影响性能和安全。

不扁平化,pnpm如何解决问题

树结构会出现问题,扁平化后也会出现问题,那么pnpm是怎么解决的呢?

pnpm在安装时,将每一个包,和它们的依赖放到同一个文件夹中。将依赖提升至和包同一层级。同时,形成与依赖树结构一致的软链接,标注每一个依赖的位置。

以express为例,当包安装完成后,我们可以看到在项目的 node_modules文件夹下,目录结构是这样的:

.pnpm
.modules.yaml
express

再打开express

▾ node_modules
    ▸ .pnpm
    ▾ express
        ▸ lib
          History.md
          index.js
          LICENSE
          package.json
          Readme.md
          .modules.yaml

这里的express只是一个符号链接,当 Node.js 解析依赖的时候,它使用这些依赖的真实位置,所以它不保留符号链接。而依赖包的真正位置,在.pnpm目录下。虽然.pnpm目录中是扁平化的结构,但是软连接的结构与依赖树完全一致。这样也解决了包的重复安装和对文件的使用权限问题。

这样的机制带来哪些优势

  • npm/yarn在不同项目依赖同一个包的情况下,会将这个包安装多次在每个项目中,而pnpm安装的包会存储在可寻址的磁盘中,在多个项目同时引用时,只需要用一个硬链接指向该地址就可以使用,大大节约了磁盘空间

  • 当依赖了同一个包的不同版本时,只对变更的文件进行更新,不需要重复下载没有变更的部分,对于时间和空间

  • 算法比 npm/yarn 的扁平化算法简单很多,节省时间

pnpm 使用

安装

直接按照官网方法安装就ok 👉 pnpm.io/zh/installa…

使用

npm 命令pnpm 等效
npm installpnpm install
npm i <pkg>[pnpm add <pkg>]
npm run <cmd>[pnpm <cmd>]

基本用法与npm大差不差,但是在配置上, pnpm 比 npm 更严格。

pnpm 支持丰富选择器语法,可以通过名称或关系选择包。

可以通过 --filter 标志指定选择器:

pnpm <command> --filter <package_selector>

详细配置信息可在官方文档查询 👉 pnpm.io/zh/package_…

参考资料: