pnpm 简介
pnpm 简介
引入
前端圈子主要使用三种包管理器npm
、yarn
和pnpm
。目前pnpm
由于其较好的综合性能,正被越来越多的人所使用。就在几个月前(2023-3-22
),它的npm
周下载量正式超过了yarn
,并且大有赶超npm
的趋势(npm
是真不作为,活该)。可以看出,pnpm
是个很火的技术。正因如此,有必要学习一下pnpm
,并深入了解它解决了哪些问题、存在哪些优势。
1. pnpm 解决了哪些问题?
在pnpm
出现之前,传统包管理器对于node_modules
结构的设计是存在缺陷的。
npm 2.x
使用的嵌套结构会导致相同的依赖被重复安装,这既增加了npm i
命令所花的时间,也占用了大量的磁盘空间- 为了解决嵌套结构的问题,
yarn
推出了扁平结构,但该结构只能部分解决嵌套结构带来的问题。对于不同版本的相同依赖,只会有一个版本的依赖被提升,其他版本的依赖仍然会被重复安装。此外由于依赖提升,项目可以访问到自己的依赖的依赖,那么项目可以不在package.json
中声明某个依赖,而是“蹭”依赖的依赖,倘若依赖更新或不再依赖原本的依赖,导致项目没办法“蹭”到依赖,这时就会报错。这个问题称为“幻影依赖”。
重复安装和幻影依赖问题都可以归咎于node_modules
结构设计的不合理,而pnpm
完美解决了这两个问题。它通过把依赖安装在全局,解决了依赖重复下载和解压的问题;此外,通过基于符号链接的node_modules
结构,解决了幻影依赖问题。
2. pnpm 底层的原理
依赖安装在全局
使用pnpm
安装依赖,所有依赖都会被安装在全局,也就是项目之外的一个公共的地方,称之为store
。通过store
可以存储所有下载过的依赖,对于新项目安装依赖时,如果该依赖存储于store
当中,就可以直接拿来用,而无需再次下载和解压。
基于符号链接的 node_modules 结构
简单来说,pnpm
把node_modules
分为了.pnpm
目录和项目依赖两部分。
对于.pnpm
,首先会存放项目中所有的依赖(即便是间接依赖)的硬链接,并通过符号链接表明依赖之间的依赖关系。
例如项目安装了依赖于 bar@1.0.0
的 foo@1.0.0
,那么pnpm
首先会创建硬链接:
node_modules
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
│ ├── index.js
│ └── package.json
└── foo@1.0.0
└── node_modules
└── foo -> <store>/foo
├── index.js
└── package.json
bar@1.0.0
和foo@1.0.0
是项目中用到的依赖,它们都硬链接到了store
目录下的依赖。由于是使用硬链接的方式进行文件共享,因此这一步并不会占用额外的磁盘空间。如果这里不理解,可以去复习一下硬链接 & 符号链接的知识,如果忘了的话这里确实不容易理解,因为磁盘上存储的是文件的具体内容,linux
实际上是通过inode
得到该文件的具体内容,而硬链接会存储inode
,因此并不会额外占用空间。
接下来,pnpm
会使用符号链接处理依赖的依赖项:
node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
└── foo@1.0.0
└── node_modules
├── foo -> <store>/foo
└── bar -> ../../bar@1.0.0/node_modules/bar
可以看到foo@1.0.0
的node_modules
下面多了bar
的符号链接。当foo@1.0.0
需要访问bar
这个依赖时,Node
会直接忽略符号链接,因此它通过查找node_modules
,会解析到bar
的实际位置.pnpm/bar@1.0.0/node_modules/bar
。
说完了.pnpm
,再说项目的直接依赖,项目的直接依赖会通过符号依赖进行链接,它们被直接放在node_modules
下:
node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
└── foo@1.0.0
└── node_modules
├── foo -> <store>/foo
└── bar -> ../../bar@1.0.0/node_modules/bar
通过这种方式,项目可以访问到foo
依赖,但是却不能访问到bar
依赖(因为node_modules
下没有bar
这个符号链接,Node
当然找不到),所以就解决了幻影依赖的问题。
3. pnpm 的优势(相比于 npm)
pnpm
和yarn
各有优劣,没办法讲哪个更好(可能pnpm
略好一点),但是和npm
相比,优势还是很大的:
- 解决了幻影依赖问题:目前
pnpm
和yarn
都解决了这个问题,只有npm
还没解决 - 安装快速:由于
pnpm
使用了全局store
存储依赖,因此对于重复的依赖,只需使用硬链接进行链接即可;而npm
需要重复下载和解压,花费更多时间 - 节省磁盘空间:
pnpm
对于同一依赖全局只存一个;而npm
无论是嵌套结构还是扁平结构,都可能会出现同一个项目的同一个依赖安装在多处的问题 - 支持更多的功能,例如可以添加补丁:目前
pnpm
和yarn
都支持patch
命令,使用该命令可以对现有的依赖进行修改(打补丁,主要是为了解决一些依赖中还没修复的bug
或是添加功能)。而npm
需要使用插件,原生不支持
4. 其他资料
这里作者回答了一些问题,例如为什么不全部用符号链接,Windows 如何做的兼容
转载自:https://juejin.cn/post/7231517390177337399