由浅入深 学习 pnpm
Why pnpm
最近公司的项目迁移使用了
pnpm
这款包管理工具,正所谓知己知彼,百战不殆。就跟着这篇文章快速的学习一下pnpm
吧
指令快速学习
// 安装 pnpm
npm install -g pnpm
// or
yarn global add pnpm
// 查看版本
pnpm -v
// 查看帮助
pnpm -h
// 安装所有的包
pnpm install // 别名 i
// 更新所有的包
pnpm update // 别名 up
// 安装某一个包
pnpm add react // dependencies
pnpm add eslint -D // devDependencies
// 移除某一个包
pnpm remove react // 别名 rm、un、uninstall
嗯嗯,已经学会了。这就去开发!
等等!这些和yarn
,npm
并没有什么区别呀,那我们为什么要使用 pnpm
呢
Store
介绍
在 pnpm
中有一个很重要的概念:store
,这个单词我们很常见,在pnpm
中,它的意思是一个全局的仓库,pnpm
他会把包缓存到store
中,我们要安装包的时候并不是优先联网下载的,是先读取的这个store
。
我们安装包到 node_modules
的过程如下
安装包的时候会同时的去看 node_modules
以及store
- 两个都没有的时候会联网下载
store
有,node_modules
没有,会从store
中复制过去store
没有,node_modules
有,也会补充store
store有关的指令
// 读取 store的位置
pnpm config get store-dir // 默认是当前磁盘下的.pnpm-store的文件夹中
// 设置 store的位置
pnpm config set store-dir "D:\env\.pnpm-store"
store的体现
// 创建文件夹
mkdir test-pnpm
// 进入
cd test-pnpm
// 初始化文件夹为一个npm项目
pnpm init Or npm init -y
// 安装 express
pnpm add express
执行规程如图
我们发现在 pnpm add
完成的时候,他会告诉我们 store
的地址,还有一个 Virtual store
的地址,这个就是当前目录下的node_modules/.pnpm
,这里路径上有一个 .pnpm
后面在讨论。
在最后输出了这样一句话
// 这里和截图不同是因为我多次下载了请忽略~
Progress: resolved 57, reused 0, downloaded 57, added 57, done
我们解析一下
resolved 57
,在下载express
这一个包的时候,解析出来这个包以及它的依赖,总共有57项。reused 0
,store
中的包重复使用了0次,毕竟我们这是第一次下载,重用是0没毛病。downloaded 57
,联网下载了 57 个包added 57
,添加到 store 中包有57项
OK,具体这些怎么体现我们可以
- 新建一个项目在安装
express
可以体现出reused
- 删掉
node_modules
在下载可以体现reused
- 不删
node_modules
,删掉store
文件夹可以体现added
- 删掉
node_modules
,删掉store
文件夹可以体现downloaded
小总结
那么到这里,我们可以了解到,pnpm
是使用了一个 store
机制,让我们下载包的速度极大的提升了
pnpm 的 node_modules解析
pnpm
的优异之处不仅仅是使用了store
加快了下载数据,还有它的node_modules
也很有意思
Tip: 我们安装包是安装到当前项目的 node_modules
下,写代码 import/require
找包是node
的机制,它找依赖是一层层的向上找node_modules
,这里我们只去了解node_modules
即可,与上面的 store
完全无关
node_modules历史
npm2 的node_modules
最早版本:npm2
这个时候我们安装一下 express,node_modules是只有一个 express文件夹的
但是展开后我们就很容易发现问题了。
我们安装的 node_modules
中有express
express
有它自己的 node_modules
express
依赖的包也有它的 node_modules
依赖的包也有它依赖包的包。。。。反正就这样一直嵌套下去了
这里会有以下几个问题
- 安装
A
B
两个包,这两个包都依赖了C
,这个时候C
就会被安装两遍,即 公共依赖会被多次安装 windows
的文件路径最长是 260 多个字符,嵌套的文件结构一直嵌套下去肯定是不行的
当时 npm
还没解决,社区就出来新的解决方案了,就是 yarn
yarn 的node_modules
yarn
解决嵌套的思路是将嵌套依赖打散到同一层,这样也就没有依赖重复多次的问题了,路径过长的问题了。
使用yarn
安装express
的文件夹结构如下
这样的打散做法很好,但不是绝对的
比如
我们安装 A
B
包
A
依赖 1.0.0
版本的C
包
B
依赖 2.0.0
版本的C
包
这个时候项目 node_modules
目录里面会有 A
B
C
包,C
包的版本是取决于安装过程先解析的是A
还是B
。如果先解析的是A
,则项目node_modules
目录中的C
包版本是1.0.0
,在B
包中依然会存在 node_modules
文件夹 ,在B
包的node_modules
中依赖 2.0.0
版本的C
包
如果先解析的B
,同理。
这样感觉也很合理,但是有一个致命的问题,叫幽灵依赖。
我们依赖的是 A
B
,但是我们在代码中是可以写 require("C")
的,也就是打散的过程中,将不是我们的依赖也打散到node_modules
中了,导致我们可以引入到C
包
并且,并没有实质性的解决我们重复依赖导致包被多次安装,占用重复的空间。
还是上面的例子,打散的是1.0.0
的C
包,如果还有一个D
包依赖2.0.0
的C
包,则 2.0.0
的C
包在 安装B
包和D
包的过程中会被安装两次!
pnpm 的node_modules
我们来看一下 pnpm 的做法
首先 node_modules
中只有一个 express
目录,但是我们发现后面多了一个链接符号,也就是说它真正的位置是不在这里的,这里只是一个软连接,保证我们在写 require("express")
的时候不会报错,这样的作法就解决了幽灵依赖的问题。
这个时候我们发现有一个 .pnpm
的文件夹,这个文件夹的秘密就太多了。
我们一点点来解密这个 .pnpm
目录
pnpm
的思路是将所有包,以及包依赖的包,等嵌套依赖的包,全部打散到.pnpm
目录中,为了解决重复安装相同版本的包的问题,他将包的版本也写到了文件名中。- 我们安装的
express
,在项目的node_modules
目录中它是一个软连接,链接到了.pnpm
目录中.pnpm/express@4.18.1/node_modules/express
目录- 注意一下这个文件结构,
.pnpm
中 是带版本号的 文件夹,这个目录中会有一个node_modules
,在这里会有一个包名的文件夹,这个文件夹中才是真正源代码所在的目录
- 注意一下这个文件结构,
- 那我们发现,
.pnpm/express@4.18.1/node_modules/
这个目录下,express
目录是真实源代码所在地,跟他同级还有很多的软连接。这个软连接表示的是express
这个包依赖的包- 那
express
这个包依赖的包,现在是一个软连接,那他真实的路径在哪呢? - 可以发现,他被打散到
.pnpm
中了,会有一个包名@版本号
的文件夹,比如express
依赖的accepts
这个包,他真实的源代码是在.pnpm/accepts@1.3.8/node_modules/accepts
文件夹下
- 那
那我们就发现了
pnpm
会把所有的依赖打散到.pnpm
目录下,会带上版本号- 在这个带版本号的文件夹下有一个
node_modules
- 这个
node_modules
中只有两种情况,一个是包名文件夹,这里是真实的源代码,包依赖的包会在当前node_modules
下以软连接的方式,连接到.pnpm/包名@版本/node_modules/包名
这个目录中
test-pnpm\node_modules\express // 这个是软连接,实际的地址如下
test-pnpm\node_modules\.pnpm\express@4.18.1\node_modules\express
// express 依赖的包 会在 下面这个目录里面生成 软连接
test-pnpm\node_modules\.pnpm\express@4.18.1\node_modules\依赖包名
// 对应的真实地址是
test-pnpm\node_modules\.pnpm\依赖包名@版本\node_modules\依赖包名
总结
pnpm
的最大特点有两个
- 使用
store
全局的缓存了包,能在安装包的时候联网下载也能从 项目的node_modules
进行备份 - 在
.pnpm
文件夹,创建包名@版本号
文件夹,以及软连接的方式,杜绝了一个版本的包被多次安装的问题,monoreport
类型的项目更加能体现出它的优势
转载自:https://juejin.cn/post/7144234186646224904