pnpm: 扁平化的 node_modules 不是唯一的方式

原文链接:Flat node_modules is not the only way,2020.05.27,by Zoltan Kochan

新用户经常问我关于 pnpm 创建的 node_modules 结构为什么如此奇怪。为什么它不是扁平化的?所有子依赖(sub-dependencies)在哪里?

我假设读者已经熟悉 npm 和 Yarn 创建的扁平化 node_modules。如果你不明白为什么 npm 3 必须从 v3 开始使用扁平化 node_modules,可以在《为什么我们应该使用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
.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express
.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
.pnpm
.modules.yaml
express
.pnpm .modules.yaml express

你可以在这里查看。

那么所有的依赖项都在哪里呢?node_modules 文件夹中只有一个名为 .pnpm 的文件夹和一个名为 express 的符号链接。我们只安装了 express,所以这也我们在应用程序唯一能够访问的包。

在这里阅读更多关于 pnpm 严格性好处的信息。

让我们来看看 express 里面有什么:

▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml
▾ node_modules

  ▸ .pnpm
  ▾ express
    ▸ lib
      History.md
      index.js
      LICENSE
      package.json
      Readme.md
  .modules.yaml
▾ node_modules ▸ .pnpm ▾ express ▸ lib History.md index.js LICENSE package.json Readme.md .modules.yaml

express 没有 node_modulesexpress 的所有依赖在哪里?

诀窍在于 express 只是一个符号链接。当 Node.js 解析依赖项时,它使用它们的真实位置,会忽略符号链接。但你可能会问,express 的真实位置在哪里呢?

这里: node_modules/.pnpm/express@4.17.1/node_modules/express

好的,现在我们知道了 .pnpm/ 文件夹的目的。.pnpm/ 将所有包存储在一个扁平化的文件夹结构中,因此每个包都可以在以这种模式命名的文件夹中找到:

.pnpm/<name>@<version>/node_modules/<name>
.pnpm/<name>@<version>/node_modules/<name>
.pnpm/<name>@<version>/node_modules/<name>

我们称之为虚拟存储目录(virtual store directory)。

译注:pnpm 的虚拟存储目录最初是 .registry.npmjs.org///node_modules/ 方式,后来才改成上述结构。因为 .pnpm 具有标识意义,类似于项目中的 .vscode、.github 的作用

这种扁平结构避免了由 npm v2 创建的嵌套 node_modules 引起的长路径问题,但与 npm v3、4、5、6 或 Yarn v1 创建的扁平 node_modules 相比,它又保持了包的隔离性。

现在让我们来看一下 express 的真实位置:

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

这是一个骗局吗?它还缺少 node_modules!pnpm 的 node_modules 结构的第二个技巧是,包的依赖关系与其真实位置所在的目录层级相同。因此,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
▾ 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
▾ 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/ 中适当目录的符号链接。将 express 的依赖放在上一级可以避免循环符号链接。

所以你可以看到,尽管 pnpmnode_modules 结构一开始看起来不寻常:

  • 它完全兼容 Node.js
  • 包和它们的依赖关系又能被很好地分组

译注:这就是 pnpm 非常巧思的地方,利用了 Node.js 查找依赖时的寻址策略(查找当前目录或上层目录中的 node_modules 目录,以此类推),配合符号链接:既解决了 npm 扁平化带来的间接依赖暴露问题又做到了依赖分组,同时借助全局存储(global store)大大节省了硬盘空间。

对于具有 peer dependencies 的包,结构稍微复杂些,但思路是相同的:使用符号链接创建一个嵌套并具有扁平化的目录结构。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYtF2GZd' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片