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的最佳我的项目实际 - 实践篇