peers 是如何被处理的
pnpm 的最佳特征之一是,在一个项目中,package
的一个特定版本将始终只有一组依赖项。 这个规则有一个例外 -那就是具有 peer dependencies 的package
。
peer 依赖项(peer dependencies)会从依赖图中更高的已安装的依赖项中解析(resolve),因为它们与父级共享相同的版本。 这意味着,如果 foo@1.0.0
有两个peers
依赖(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
中。 这两个包都有依赖包 baz 和 bar, 但是它们却依赖着不同版本的 baz。 因此, foo@1.0.0
有两组不同的依赖项:一组具有 baz@1.0.0
,另一组具有 baz@1.1.0
。 若要支持这些用例,pnpm 必须有几组不同的依赖项,就去硬 链接几次 foo@1.0.0
。
通常,如果一个package
没有 peer 依赖项(peer dependencies),它会被硬链接到其依赖项的软连接(symlinks)旁的 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 依赖(peer dependencies),那么它可能就会有多组依赖项,所以我们为不同的 peer 依赖项创建不同的解析:
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
我们创建 foo@1.0.0_bar@1.0.0+baz@1.0.0
或foo@1.0.0_bar@1.0.0+baz@1.1.0
内到foo
的软链接。 因此,Node.js 模块解析器将找到正确的 peers。
如果一个package
没有 peer 依赖(peer dependencies),不过它的依赖项有 peer 依赖,这些依赖会在更高的依赖图中解析, 则这个传递package
便可在项目中有几组不同的依赖项。 例如,a@1.0.0
具有单个依赖项 b@1.0.0
。 b@1.0.0
有一个 peer 依赖为 c@^1
。 a@1.0.0
永远不会解析b@1.0.0
的 peer, 所以它也会依赖于 b@1.0.0
的 peer 。
以下是该结构在 node_modules
的情况。 在这个例子中,a@1.0.0
需要在项目的node_modules
中出现两次 - 其中一次是被 c@1.0.0
resolve,另一次被 c@1.1.0
再次 resolve。
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