pnpm简介

pnpm简介

pnpm是什么

和npm,yarn一样,pnpm是一个包管理工具。不一样的是,pnpm解决了npm和yarn一直都没有解决的痛点。在许多方面比npm和yarn更优秀。

pnpm对比npm/yarn的优点

  • 更快速的依赖下载
  • 更高效的利用磁盘空间
  • 更优秀的依赖管理

更快速的依赖下载

根据官方提供的数据
官方数据
从图上我们可以看出,pnpm平均比npm和yarn快上2~3倍。这一点在依赖的下载上额外明显。

更高效的利用磁盘空间

为什么说pnpm会比npm和yarn更高效的利用磁盘空间?
pnpm 有一个store的概念(是一块存储文件的空间,后面会说到),内部使用"基于内容寻址"的文件系统来存储磁盘上所有的文件,这一套系统的优点是:

不会重复下载依赖

举个例子 假设出现这么一个情况↓
alt

你4个项目都依赖了express.js(第三方插件)。如果是npm/yarn的话,express.js就会被安装4个在你的磁盘空间当中。从而出现下面这个情况↓
alt
但是pnpm 得益于"基于内容寻址"的文件系统,使用pnpm下载的文件不论被多少项目所依赖,都只会在磁盘中写入一次。后面再有项目使用的时候会采用硬链接的方式去索引那一块磁盘空间。
所以,在同样被多个项目依赖的时候,pnpm对磁盘的占用如下↓
alt
如果有一天你所依赖的版本提升了。假设从express@2.0升级到了express@3.0。而express@3.0比express@2.0多了20个文件。这个时候pnpm并不会删除express@2.0再去重新下载express@3.0。而是复用express@2.0原本的磁盘内容。再在express@2.0的基础上增加20个文件形成express@3.0。

更优秀的依赖管理

在npm1和npm2的时候。依赖结构是这样的↓

node_modules 
└─ 依赖A 
   ├─ index.js 
   ├─ package.json 
   └─ node_modules 
       └─ 依赖B 
       ├─ index.js 
       └─ package.json
 └─ 依赖C 
   ├─ index.js 
   ├─ package.json 
   └─ node_modules 
       └─ 依赖B 
       ├─ index.js 
       └─ package.json

上面这种结构会导致哪些问题呢?让我们来分析下。

  • 依赖包会被重复安装
  • React实例无法共享
  • 依赖层级太多问题

A依赖B,C也依赖B。也就是说B同时是A和C的依赖。这种情况下。B会被下载两次。
npm1和npm2的运行逻辑是,某一个包被其他包依赖N次,就需要被下载N次。也就是我们所说的重复安装。

npm3和yarn中平铺的结构依然存在的问题

上述npm1和npm2的这些问题在npm3+和yarn中得到了解决

从npm3开始。npm3和yarn都采用了"扁平化依赖"来解决上述问题。

node_modules 
└─ 依赖A  
    ├─ index.js 
    ├─ package.json 
    └─ node_modules 
└─ 依赖C   
    ├─ index.js 
    ├─ package.json 
    └─ node_modules 
└─ 依赖B 
    ├─ index.js 
    ├─ package.json 
    └─ node_modules 

所有的依赖都会被平铺到同一层面。这样,因为require寻找包的机制。如果A和C都依赖了B。那么A和C在自己的node_modules中未找到依赖C的时候会向上寻找,并最终在与他们同级的node_modules中找到依赖包C。
这样,就不会出现重复下载的情况。而且依赖层级嵌套也不会太深。因为没有重复的下载,所有的A和C都会寻找并依赖于同一个B包。自然也就解决了实例无法共享数据的问题
这种平铺的结构看似完美,但其实依然存在一些细节上的问题。

  • 依赖结构的不确定性
  • 扁平化算法的复杂度比较高,相对的比较耗时
  • 项目中还是存在可以非法访问的问题

pnpm解决了这些问题

pnpm init 

pnpm install express

然后你就会发现,express直接出现在了node_modules下面,他的依赖并没有和他处于同一目录下,而他本身目录下也不具备node_modules。像这样↓

alt
因为node_modules下面的express仅仅只是一个软连接,pnpm直接抛弃了npm3/yarn原本在项目级别的扁平化结构。项目级别的node_modules下用软链接(什么是软连接?_百度知道 (baidu.com))代替。
那express的依赖又去了哪里?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8lw8L15B-1658892063251)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0326ee80083d4bf3bfc3dec4dda0144e~tplv-k3u1fbpfcp-zoom-in-crop-mark:3024:0:0:0.awebp?)]
最后我们在.pnpm/express@version/node_modules/ 下面找到了express的依赖。
使用pnpm下载的所有依赖都会以.pnpm/依赖名@版本号/node_modules/这种形式被存储。
乍一看,好像又从扁平化管理回到嵌套结构了。性能不是倒退了吗?
不是的。
一开始从npm1和npm2的嵌套结构变成扁平化结构是为了解决

  • 包被重复安装
  • 依赖示例无法共享
  • 依赖层级太深

这三个问题。而.pnpm/依赖名@版本号/node_modules/下面的依赖也全部都是软连接。这些软连接指向存储在store中的文件。(store是pnpm的文件公共存储空间,在后面会有介绍)

alt
发现这种设计的巧妙之处了吗。
因为.pnpm/依赖名@版本号/node_modules/下面都是软连接,他们指向同一块存储空间。所以也就不存了包会重复安装和依赖实例无法共享的问题。
而,express所有的依赖都会在.pnpm/依赖名@版本号/node_modules/这个目录下被扁平化处理,同样解决了依赖结构太深的问题。
还有将包本身和依赖放到同一目录下,这样,利用require的特性也能够找到所有的依赖包。再将包本身的软连接放到外层的node_modules中。这样,node_modules中的包在结构上就几乎和package.json中的内容保持一致。为什么说几乎一致而不是完全一致?因为有些包有变量提升,会被提升到外层node_modules中。但是大体上还是一样的。
到这里,pnpm就又解决了npm3/yarn当时没有解决的依赖结构的不确定性。

关于npm3/yarn未解决的非法访问问题

当我们再项目中引用的时候,他会去node_modules中去寻找。由上图可知,只会在node_modules下面的第一层去寻找!!! 而pnpm的机制会让node_moduels下只有一级依赖包的软链接(也就是说如果你下载一个express,那么项目级别的node_modules下就只有express的软连接而没有express的依赖包的软链接)。所以如果你在自己的项目中直接去引用二级依赖包的话,会报错,直接找不到 (如上图) 。
可能有些同学还不理解,没关系,我们再举个例子。
我们下载了一个 A包。A包的软连接在项目级别的node_modules中,但是A包的所有依赖包都在.pnpm/依赖名@版本号/node_modules/下面。假设C包是A包的依赖包。我们直接在项目中使用require/import引用C包的话。require/import会去项目级别的node_modules中寻找。然后就会发现项目级别的node_modules下面只有一个A包的软连接,没有A包的依赖C包,找不到,就会报错。这样,只要C包没有在项目的package.json中声明,就无法访问(避免了非法访问)。
所以。到这里。pnpm也解决了npm3和yarn中非法访问的问题。
而且,非法访问的这个问题以当前的npm和yarn的版本,使用在项目级别的node_modules下进行扁平化的管理的机制,几乎无法避免。pnpm却完美的解决了。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值