为了提高英语水平和保持技术成长,开始按计划翻译一些短篇和博客,有问题欢迎讨论👻
原文:Flat node_modules is not the only way
原作者:Zoltan Kochan
正文
pnpm的新用户经常问我关于pnpm创建后的node_module
结构为什么这么奇怪。为什么不是扁平化的?所有的次级依赖在哪里?
我假设阅读这篇文章的读者都已经熟悉了npm和yarn创建后的扁平化
node_modules
,如果你不明白npm在v3中开始使用扁平化node_modules
,你可以在Why should we use pnpm?中找到一些历史说明
那么为什么pnpm的node_modules
不寻常呢?我们来创建两个目录,一个运行npm add express
,另一个运行pnpm add express
,下面是你在第一个目录的node_modules
中得到的顶部内容结构
.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express
你可以在这里看到整个目录。
然后这是你在pnpm创建的node_modules
中得到的目录:
.pnpm
.modules.yaml
express
你可以在这里查看.
那么,所有的依赖项都在哪里呢,在node_modules
中只有一个叫做.pnpm
的文件夹和一个叫做express
的symlink
。好吧,因为我们只安装了express
,所以这是你的应用可以访问的唯一package
在此阅读更多关于pnpm的严格性为什么是一件好事情
让我们看看express
的内部:
▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml
express没有node_modules?express的所有依赖项在哪里?
诀窍在于,express
只是一个symlink
,但Node.js
解析依赖关系时,它会使用express
的真实位置,所以依赖不会保留在符号连接上,但是你可能会问,express
的真实位置在哪?
这里:node_modules/.pnpm/express@4.17.1/node_modules/express.
现在我们知道了.pnpm
文件夹的用途。.pnpm
在一个扁平的文件夹结构中存储所有的packages
,所以每个package
都可以在这个模式命名的文件夹中找到
.pnpm/<name>@<version>/node_modules/<name>
我们称它为虚拟存储目录
这种扁平结构避免了npm v2
创建的嵌套node_modules
造成的长路径问题,但是又与npm v3,4,5,6
和yarn v1
的扁平化结构不同,保持了packages
的隔离
现在我们来研究一下express的真实位置:
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
这是错误的吗?它仍然缺少node_modules
!pnpm
的node_modules
结构的第二个诀窍是,packages
的依赖关系在同一级的目录上,而package
依赖的真正位置在这个目录上。所以express
的依赖不在.pnpm/express@4.17.1/node_modules/express/node_modules/
,而是在.pnpm/express@4.17.1/node_modules/
▾ node_modules
▾ .pnpm
▸ accepts@1.3.5
▸ array-flatten@1.1.1
...
▾ express@4.16.3
▾ node_modules
▸ accepts
▸ array-flatten
▸ body-parser
▸ content-disposition
...
▸ etag
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
express
的所有依赖都是指向node_modules/.pnpm
内目录的symlinks。express
的依赖放在上一级,可以避免循环symlinks
所以你可以看到,尽管pnpm的node_modules
结构从开始时看起来不寻常:
- 完全兼容Node.js
- packages和相关依赖被很好的组合在一起
对于同样依赖关系的packages来说结构要复杂一些,但是想法是一样的:使用symlinks创建一个有扁平目录结构的嵌套