为什么要推荐使用pnpm

在谈起pnpm时先来聊一聊之前的npm和yarn有什么存在的问题 

npm2

在npm3之前我们安装依赖的目录是这样:

node_modules
├────packageA
├────node_modules
│   ├────packageB
│   ├────node_modules
│        ├────packageC
│        ├────node_modules

只要安装依赖下赖依赖于其他依 就会套一层node_modules  如果当前层级还有其他依赖呢?思路也很简单,我再给你套一层node_modules,以此类推

这样做会有什么问题呢?

  • windows一般有一个最大的路径的长度限制 字符到了一定位数后就不能在进行访问
  • 资源浪费,例如 A 和 B 都使用了C 就会再A包下面有一个C B包下面又会有一个C 这就浪费了空间上的消耗

yarn/npm3

这个方法是yarn先提出来的,npm3紧随其后

解决思路:  node_modules扁平化

node_modules
├────packageA
├────packageB
├────packageC

这样我们安装的依赖呢 就解决了上面两个问题,如果当前依赖下依赖其他依赖,直接提升到根目录的node_modules下,这样及可以解决路径长度问题又解决了资源不共享问题。

但是呢,同样就会出现新问题

  1. 扁平化可以访问他们不依赖的包 可能会有安全问题 (平铺都是同级的,谁都可以访问,也就是常说的幽灵依赖)
  2. 平坦依赖树的算法非常复杂 下载就很浪费计算的时间
  3. 某些包必须复制到一个项目节点模块文件夹中 (有些包不能被拉平 会出现问题,一般问题出现多个版本只能提升一个)

pnpm

pnpm代表什么?pnpm代表 performant(高性能的)npm

pnpm的优点

  • 快速:pnpm 比其他包管理器快 2 倍
  • 高效:node_modules 中的文件为复制或链接自特定的内容寻址存储库
  • 支持 monorepos:pnpm 内置支持单仓多包
  • 严格:pnpm 默认创建了一个非平铺的 node_modules,因此代码无法访问任意包

那pnpm到底解没解决上面的问题呢?为了测试 分别使用npm 和 pnpm 下载axios包

npm i axios
// and
pnpm i axios

 从下载来看呢 目前可以解决 幽灵依赖问题 也就是说pnpm并没有使用扁平化的方式,那么pnpm 下载下来的会不会嵌套很多层级呢?

注意看axios文件上有一个小箭头,返回看你的桌面上是不是所有的软件上都带上一个箭头呢?他呢其实就是软链接本质上就是快捷方式,而且在包上面还有一个.pnpm的文件,存在即合理,必然有他的用处,当前看到的axios就是通过.pnpm目录下axios进行软链接,然后再通过.pnpm下的axios和磁盘目录下的.pnpm-store进行建立硬链接。

当然听起来比较抽象,接下来解释下什么是硬链接/软链接。

硬链接

基维百科:硬链接(英语:hard link)是计算机文件系统中的多个文件平等地共享同一个文件存储单元(如MFT条目inode

如何建立硬链接?

新建出一个文本文件 随意写上文字 例如a.text  准备为a建立硬链接

以windows为例执行cmd命令

E:\项目\test\硬链接>mklink /h b.txt a.txt

 

这时候同级目录下就会产生一个b.txt 打开正是a.txt的文字内容,这时候不管你修改a还是b他们都会进行互相修改,原因就是使用了硬链接修改了同一个磁盘的地址。可以理解成js的赋值对象

let a = {}
let b = a

 

软链接

基维百科:软链接符号链接、Symbolic link)是一类特殊的文件, 其包含有一条以绝对路径或者相对路径的形式指向其它文件或者目录的引用。

同理新建a文本文件

E:\项目\test\软链接>mklink b.txt a.txt

 

 打开b.txt 就会 打开的a.txt文本,通过路径引用到a.txt

接下来再看pnpm的目录流程

每次硬链接都是从 .pnpm store 进行链接,pnpm有什么好处呢?

  1. 使用npm时 每次依赖被不同的项目使用,都会重新安装一次 但是pnpm 依赖会被存储内容可寻地址的存储中 会使用硬链接给拿出来 (只要之前下载过,下次直接使用硬链接)
  2. 如果有依赖版本有更新, 100个文件内只更新了一个 pnpm update只会 向存储中心更新一个版本,而不会因为一个文件重新下载依赖。
  3. 所有下载的依赖会下载到一开始安装到的 pnpm目录下的存储地址,只不过他是一个虚拟的存储,这样每个项目都可以访问到这个依赖。

.pnpm store存在哪里呢?

在pnpm i 的时候就已经告诉你了,默认情况下是在磁盘根目录下的.pnpm-store

 为什么不是在其他磁盘?

原因是硬链接只能在当前磁盘上进行链接,不能跨磁盘访问。

注意在倒数第二行 downLoad是 0 ,也就是没有进行下载,直接从.pnpm-store 进行硬链接起来。

如果包存储在全局存储中,为什么我的 node_modules 使用了磁盘空间?

官网回答:pnpm 创建从全局存储到项目下 node_modules 文件夹的 硬链接。 硬链接指向磁盘上原始文件所在的同一位置。 例如,如果您的项目有 foo 作为依赖者 并且它占用了 1MB 的空间。 然后看起来它将占用了 项目的 node_modules 文件夹和全局的 存储空间相同的空间。 但是,该 1MB 是磁盘上两个不同位置的相同空间 。 所以 foo 总共占用 1MB,而不是 2MB。 大白话也就是值只占用了同一个空间。

pnpm的缺点:

  • 每次安装都是存储在全局上 这样,全局的pnpm-store占用比较大,但是比起每个项目都存在一个node_modules是比较好的。
  • 项目删除后依赖不会被删除。

如果想彻底删除一个不再使用的包,可以使用pnpm的剪裁  

pnpm store prune

和npm对比命令

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

猜你喜欢

转载自blog.csdn.net/m0_46846526/article/details/129611061