【翻】Flat node_modules is not the only way

为了提高英语水平和保持技术成长,开始按计划翻译一些短篇和博客,有问题欢迎讨论👻
原文: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的文件夹和一个叫做expresssymlink。好吧,因为我们只安装了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,6yarn v1的扁平化结构不同,保持了packages的隔离

现在我们来研究一下express的真实位置:

▾ express
  ▸ lib
    History.md
    index.js
    LICENSE
    package.json
    Readme.md

这是错误的吗?它仍然缺少node_modulespnpmnode_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结构从开始时看起来不寻常:

  1. 完全兼容Node.js
  2. packages和相关依赖被很好的组合在一起

对于同样依赖关系的packages来说结构要复杂一些,但是想法是一样的:使用symlinks创建一个有扁平目录结构的嵌套