前言
置信小伙伴们都接触过npm/yarn
,这两种包管理工具想必是大家工作中用的最多的包管理工具,npm
作为node
官网的包管理工具,它是随着node的诞生一起呈现在大家的视线中,而yarn
的呈现则是为了解决npm
带来的诸多问题,尽管yarn
进步了依赖包的装置速度与应用体验,但它仍旧没有解决npm
的依赖反复装置等致命问题。pnpm的呈现完满解决了依赖包反复装置的问题,并且实现了yarn
带来的所有优良体验,所以说pnpm才是前端工程化我的项目的将来。
如果这篇文章有帮忙到你,❤️关注+点赞❤️激励一下作者,文章公众号首发,关注 前端南玖
第一工夫获取最新文章~
npm 与 yarn 存在的问题
晚期的npm
在npm\@3之前,node_modules
构造能够说是整洁
、可预测
的,因为过后的依赖构造是这样的:
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
每个依赖上面都保护着本人的node_modules
,这样看起来的确十分整洁,但同时也带来一些较为重大的问题:
- 依赖包反复装置
- 依赖层级过多
- 模块实例无奈共享
依赖包反复装置
从下面的依赖构造咱们能够看出,依赖A与依赖C同时援用了依赖B,此时的依赖B会被下载两次。此刻咱们想想要是某一个依赖被援用了n次,那么它就须要被下载n次。(此时心里是不是在想,怎么会有如此坑的设计)
依赖层级过多
咱们再来看另外一种依赖构造:
node_modules └─ 依赖A ├─ index.js ├─ package.json └─ node_modules └─ 依赖B ├─ index.js ├─ package.json └─ node_modules └─ 依赖C ├─ index.js ├─ package.json └─ node_modules └─ 依赖D ├─ index.js └─ package.json
这种依赖层级少还能承受,要是依赖层级多了,这样一层一层嵌套上来,就像一个依赖天堂,不利于保护。
npm\@3与yarn
为了解决上述问题,npm3
与yarn
都抉择了扁平化构造,也就是说当初咱们看到的node_modules
外面的构造不再有依赖嵌套了,都是如下依赖构造:
node_modules └─ 依赖A ├─ index.js ├─ package.json └─ node_modules └─ 依赖C ├─ index.js ├─ package.json └─ node_modules └─ 依赖B ├─ index.js ├─ package.json └─ node_modules
node_modules
下所有的依赖都会平铺到同一层级。因为require寻找包的机制,如果A和C都依赖了B,那么A和C在本人的node\_modules中未找到依赖C的时候会向上寻找,并最终在与他们同级的node\_modules中找到依赖包C。 这样就不会呈现反复下载的状况。而且依赖层级嵌套也不会太深。因为没有反复的下载,所有的A和C都会寻找并依赖于同一个B包。天然也就解决了实例无奈共享数据的问题
因为这个扁平化构造的特点,想必大家都遇到了这样的体验,本人明明就只装置了一个依赖包,关上node_modules
文件夹一看,外面却有一大堆。
这种扁平化构造尽管是解决了之前的嵌套问题,但同时也带来了另外一些问题:
- 依赖构造的不确定性
- 扁平化算法的复杂度减少
- 我的项目中依然能够非法拜访没有申明过的依赖包(幽灵依赖)
依赖构造的不确定性
这个怎么了解,为什么会产生这种问题呢?咱们来认真想想,退出有如下一种依赖构造:
A包与B包同时依赖了C包的不同版本,因为同一目录下不能呈现两个同名文件,所以这种状况下同一层级只能存在一个版本的包,另外一个版本还是要被嵌套依赖。
那么问题又来了,既然是要一个扁平化一个嵌套,那么这时候是如何确定哪一个扁平化哪一个嵌套的呢?
这两种构造都有可能,精确点说哪个版本的包被晋升,取决于包的装置程序!
这就是为什么会产生依赖构造的不确定
问题,也是 lock 文件
诞生的起因,无论是package-lock.json
(npm 5.x 才呈现)还是yarn.lock
,都是为了保障 install 之后都产生确定的node_modules
构造。
尽管如此,npm/yarn 自身还是存在扁平化算法简单
和package 非法拜访
的问题,影响性能和平安。
pnpm
后面说了那么多的npm
与yarn
的毛病,当初再来看看pnpm是如何解决这些难堪问题的。
什么是pnpm
疾速的,节俭磁盘空间的包管理工具
就这么简略,说白了它跟npm
与yarn
没有区别,都是包管理工具。但它的独特之处在于:
- 包装置速度极快
- 磁盘空间利用十分高效
个性
安装包速度快
从上图能够看出,pnpm
的包装置速度显著快于其它包管理工具。那么它为什么会比其它包管理工具快呢?
咱们来能够来看一下各自的装置流程
- npm/yarn
- resolving:首先他们会解析依赖树,决定要fetch哪些安装包。
- fetching:装置去fetch依赖的tar包。这个阶段能够同时下载多个,来减少速度。
- wrting:而后解压包,依据文件构建出真正的依赖树,这个阶段须要大量文件IO操作。
- pnpm
上图是pnpm的装置流程,能够看到针对每个包的三个流程都是平行的,所以速度会快很多。当然pnpm会多一个阶段,就是通过链接组织起真正的依赖树目录构造。
磁盘空间利用十分高效
pnpm 外部应用基于内容寻址
的文件系统来存储磁盘上所有的文件,这个文件系统杰出的中央在于:
- 不会反复装置同一个包。用 npm/yarn 的时候,如果 100 个我的项目都依赖 lodash,那么 lodash 很可能就被装置了 100 次,磁盘中就有 100 个中央写入了这部分代码。但在应用 pnpm 只会装置一次,磁盘中只有一个中央写入,前面再次应用都会间接应用
hardlink
。 - 即便一个包的不同版本,pnpm 也会极大水平地复用之前版本的代码。举个例子,比方 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会从新写入 101 个文件,而是保留原来的 100 个文件的
hardlink
,仅仅写入那一个新增的文件
。
反对monorepo
pnpm 与 npm/yarn 另外一个很大的不同就是反对了 monorepo,pnpm内置了对monorepo的反对,只需在工作空间的根目录创立pnpm-workspace.yaml和.npmrc配置文件,同时还反对多种配置,相比拟lerna和yarn workspace,pnpm解决monorepo的同时,也解决了传统计划引入的问题。
monorepo 的主旨就是用一个 git 仓库来治理多个子项目,所有的子项目都寄存在根目录的packages
目录下,那么一个子项目就代表一个package
。
依赖治理
pnpm应用的是npm version 2.x相似的嵌套构造,同时应用.pnpm 以平铺的模式贮存着所有的包。而后应用Store + Links和文件资源进行关联。简略说pnpm把会包下载到一个公共目录,如果某个依赖在 sotre 目录中存在了话,那么就会间接从 store 目录外面去 hard-link,防止了二次装置带来的工夫耗费,如果依赖在 store 目录外面不存在的话,就会去下载一次。通过Store + hard link的形式,使得我的项目中不存在NPM依赖天堂问题,从而完满解决了npm3+和yarn中的包反复问题。
咱们别离用npm
与pnpm
来装置vite比照看一下
npm | pnpm |
---|---|
所有依赖包平铺在node_modules 目录,包含间接依赖包以及其余次级依赖包 | node_modules 目录下只有.pnpm 和间接依赖包,没有其余次级依赖包 |
没有符号链接(软链接) | 间接依赖包的前面有符号链接(软链接)的标识 |
pnpm装置的vite
所有的依赖都软链至了 node_modules/.pnpm/
中的对应目录。 把 vite
的依赖搁置在同一级别防止了循环的软链。
软链接 和 硬链接 机制
pnpm 是通过 hardlink 在全局外面搞个 store 目录来存储 node\_modules 依赖外面的 hard link 地址,而后在援用依赖的时候则是通过 symlink 去找到对应虚构磁盘目录下(.pnpm 目录)的依赖地址。
这两者联合在一起工作之后,如果有一个我的项目依赖了 A@1.0.0
和 B@1.0.0
,那么最初的 node\_modules 构造出现进去的依赖构造可能会是这样的:
node_modules└── A // symlink to .pnpm/A@1.0.0/node_modules/A└── B // symlink to .pnpm/B@1.0.0/node_modules/B└── .pnpm ├── A@1.0.0 │ └── node_modules │ └── A -> <store>/A │ ├── index.js │ └── package.json └── B@1.0.0 └── node_modules └── B -> <store>/B ├── index.js └── package.json
node_modules
中的 A 和 B 两个目录会软连贯到 .pnpm 这个目录下的实在依赖中,而这些实在依赖则是通过 hard link 存储到全局的 store 目录中。
store
pnpm
下载的依赖全副都存储到store
中去了,store
是pnpm
在硬盘上的公共存储空间。
pnpm
的store
在Mac/linux中默认会设置到{home dir}>/.pnpm-store/v3
;windows下会设置到以后盘符的根目录下。应用名为 .pnpm-store的文件夹名称。
我的项目中所有.pnpm/依赖名@版本号/node_modules/
下的软连贯都会连贯到pnpm
的store
中去。
原文首发地址点这里,欢送大家关注公众号 「前端南玖」,如果你想进前端交换群一起学习,请点这里
我是南玖,咱们下期见!!!