【翻】How peers are resolved

为了提高英语水平和保持技术成长,开始按计划翻译一些短篇和博客,有问题欢迎讨论👻
原文:How peers are resolved

正文

pnpm最大的一个特点是,在一个项目中,一个特定版本的package总是有一组依赖关系。不过,这个规则有一个例外–有peer dependencies的packages

在dependency graph中,peer dependencies是从更高级别的依赖中解析的,因为它们与它们的父依赖项共享相同的版本。这意味着如果foo@1.0.0有两个peer依赖项(bar@^1 和 baz@^1),那么在同一个项目中它可能会有多个不同的依赖项集合

- foo-parent-1
  - bar@1.0.0
  - baz@1.0.0
  - foo@1.0.0
- foo-parent-2
  - bar@1.0.0
  - baz@1.1.0
  - foo@1.0.0

在上面这个例子中,foo@1.0.0是在foo-parent-1和foo-parent-2安装的。这两个packages中都有bar和baz,但是他们依赖不同版本的baz。因此,foo@1.0.0有两个不同的依赖集:一个是baz@1.0.0,另一个是baz@1.1.0。为了支持这些用例,pnpm必须hand link foo@1.0.0,次数和不同的依赖集一样多。

通常,如果一个package没有peer依赖项,它会与其依赖项的symlinks一起hard linked到node_modules文件夹中,就像:

node_modules
└── .pnpm
    ├── foo@1.0.0
    │   └── node_modules
    │       ├── foo
    │       ├── qux   -> ../../qux@1.0.0/node_modules/qux
    │       └── plugh -> ../../plugh@1.0.0/node_modules/plugh
    ├── qux@1.0.0
    ├── plugh@1.0.0

然后,如果foo有peer dependencies,它可能有多组依赖关系,所以我们为不同的peer dependencies 创建不同的集合:

node_modules
└── .pnpm
    ├── foo@1.0.0_bar@1.0.0+baz@1.0.0
    │   └── node_modules
    │       ├── foo
    │       ├── bar   -> ../../bar@1.0.0/node_modules/bar
    │       ├── baz   -> ../../baz@1.0.0/node_modules/baz
    │       ├── qux   -> ../../qux@1.0.0/node_modules/qux
    │       └── plugh -> ../../plugh@1.0.0/node_modules/plugh
    ├── foo@1.0.0_bar@1.0.0+baz@1.1.0
    │   └── node_modules
    │       ├── foo
    │       ├── bar   -> ../../bar@1.0.0/node_modules/bar
    │       ├── baz   -> ../../baz@1.1.0/node_modules/baz
    │       ├── qux   -> ../../qux@1.0.0/node_modules/qux
    │       └── plugh -> ../../plugh@1.0.0/node_modules/plugh
    ├── bar@1.0.0
    ├── baz@1.0.0
    ├── baz@1.1.0
    ├── qux@1.0.0
    ├── plugh@1.0.0

我们要么创建symlinks到foo@1.0.0_bar@1.0.0+baz@1.0.0中的foo,要么创建symlinks到foo@1.0.0_bar@1.0.0+baz@1.1.0中的foo。因此,Node.js模块解析可以找到正确的peers依赖项。

如果一个package没有peer依赖项,但是有依赖于已在图中解析的同级依赖项的依赖项,那么这个transitive package可以以不同的依赖项集出现在项目中。例如,存在一个版本为a@1.0.0的包,它只有一个依赖项b@1.0.0b@1.0.0有一个同级依赖项c@^1a@1.0.0永远不会解析b@1.0.0的同级依赖项,所以它也会依赖于b@1.0.0的同级依赖项。

下面是这个结构在node_modules中的样子,在这个例子中,a@1.0.0需要在项目的node_modules中出现两次,一次和c@1.0.0,另一次和c@1.1.0解决。

node_modules
└── .pnpm
    ├── a@1.0.0_c@1.0.0
    │   └── node_modules
    │       ├── a
    │       └── b -> ../../b@1.0.0_c@1.0.0/node_modules/b
    ├── a@1.0.0_c@1.1.0
    │   └── node_modules
    │       ├── a
    │       └── b -> ../../b@1.0.0_c@1.1.0/node_modules/b
    ├── b@1.0.0_c@1.0.0
    │   └── node_modules
    │       ├── b
    │       └── c -> ../../c@1.0.0/node_modules/c
    ├── b@1.0.0_c@1.1.0
    │   └── node_modules
    │       ├── b
    │       └── c -> ../../c@1.1.0/node_modules/c
    ├── c@1.0.0
    ├── c@1.1.0