pnpm 的 node_modules 结构设计
剖析 pnpm 之前,先说一下 npm 当初的一些问题
npm 的问题
- 平时咱们应用
npm install
命令后,node_modules 就会出现以下相似内容 - 之所以呈现这种扁平的构造,最后时初衷是好的,为了更好的利用资源,把每个依赖全副放到顶层,这样就不会造成每个依赖嵌套过深,导致很多反复依赖文件
-
然而随着这种文件构造逐渐应用后,就会裸露进去两个问题
- 幽灵依赖
- 版本抵触
- 幽灵依赖就是你在援用 npm 包时,你会发现一些没有在
package.json
中呈现的包也能援用,这个就是幽灵依赖,这是因为你在 install 下载 npm 包时,npm 包也有它的依赖会下载,然而下载的依赖也会存在 node_modules 同一层级下,这样就会导致能够间接援用 -
版本抵触是因为不同的依赖可能依赖的包版本也不同,然而 node_modules 的同一层级只能存在一个包的一个版本号,如果有不同的版本号就只能存在依赖包的 node_modules 中,这样就会导致呈现反复资源
├── package-A @1.0 |── package-B @1.0 ├── package-C @1.0 │ └── package-A @2.0 │ └── package-B @2.0 ├── package-D @1.0 │ └── package-A @2.0 │ └── package-B @2.0
pnpm 的呈现
-
在所有前端苦 npm 久已时,pnpm 呈现了,并且在 pnpm 官网的简介上就简略阐明了它的结构:
store + link
- store 就是依赖的理论存储地位,Mac/linux 在
{home dir}>/.pnpm-store/v3
,windows 在以后盘 /.pnpm-store/v3
。这样就会有个益处,你在多个我的项目应用的是同一个依赖时,就不必反复下载,这样就极大的缩小存储空间 -
link 是指符号链接 (
SymbolicLink
) 和硬链接(HardLink
)- SymbolicLink 是一种非凡的文件,蕴含一条以绝对路径或者相对路径的模式指向其余文件或者目录的援用,它的存在不依赖于指标文件,如果指标文件被删除或者挪动,指向指标文件的符号链接仍然存在,然而它们会指向一个不复存在的文件
- 相比于 SymbolicLink,HardLink 不是援用文件,而是援用inode,inode 是文件系统的一种数据结构,用于形容文件系统对象。所以你即便更改指标文件的内容或地位,HardLink 依然指向指标文件,因为 inode 指向该文件
- store 就是依赖的理论存储地位,Mac/linux 在
-
而后拿 react 举例,当
pnpm add react
后,在 node_modules 终端输出tree -a -L 3
会失去以下 node_modules 构造. ├── .modules.yaml ├── .pnpm │ ├── js-tokens@4.0.0 │ │ └── node_modules │ ├── lock.yaml │ ├── loose-envify@1.4.0 │ │ └── node_modules │ ├── node_modules │ │ ├── .bin │ │ ├── js-tokens -> ../js-tokens@4.0.0/node_modules/js-tokens │ │ └── loose-envify -> ../loose-envify@1.4.0/node_modules/loose-envify │ └── react@18.2.0 │ └── node_modules └── react -> .pnpm/react@18.2.0/node_modules/react
- node_modules 下除了.pnpm 外只有一个 react,这个 react 只是一个 SymbolicLink,当 node.js 解析时,会找到 react 的实在地位
node_modules/.pnpm/react@18.2.0/node_modules/react
- .pnpm 就是将所有依赖放在同一层文件夹中,每个包都能够通过
.pnpm/<name>@<version>/node_modules/<name>
这种门路找到,而后通过hand link
的形式在 store 中援用依赖文件 - 通过这种文件构造,pnpm 就解决了 npm 的两个问题,首先 node_modules 下不会有你未在 package.json 中申明的依赖,这样就不会有幽灵依赖的问题。而后.pnpm 下会有 name+version 的形式链接到 store 中,这样就不会呈现因为版本抵触造成资源重复的问题
参考资料
- Flat node_modules is not the only way
- Symlinked node_modules structure
- One For All:基于 pnpm + lerna + typescript 的最佳我的项目实际 – 实践篇