peers 是如何被处理的

pnpm 的最佳特征之一是,在一个项目中,package的一个特定版本将始终只有一组依赖项。 这个规则有一个例外 -那就是具有 peer dependenciespackage

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

  1. - foo-parent-1
  2. - bar@1.0.0
  3. - baz@1.0.0
  4. - foo@1.0.0
  5. - foo-parent-2
  6. - bar@1.0.0
  7. - baz@1.1.0
  8. - foo@1.0.0

在上面的示例中, foo@1.0.0 已安装在 foo-parent-1foo-parent-2 中。 Both packages have bar and baz as well, but they depend on different versions of 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,就像这样:

  1. node_modules
  2. └── .pnpm
  3. ├── foo@1.0.0
  4. └── node_modules
  5. ├── foo
  6. ├── qux -> ../../qux@1.0.0/node_modules/qux
  7. └── plugh -> ../../plugh@1.0.0/node_modules/plugh
  8. ├── qux@1.0.0
  9. ├── plugh@1.0.0

但是,如果 foo 有 peer 依赖(peer dependencies),那么它可能就会有多组依赖项,所以我们为不同的 peer 依赖项创建不同的解析:

  1. node_modules
  2. └── .pnpm
  3. ├── foo@1.0.0_bar@1.0.0+baz@1.0.0
  4. └── node_modules
  5. ├── foo
  6. ├── bar -> ../../bar@1.0.0/node_modules/bar
  7. ├── baz -> ../../baz@1.0.0/node_modules/baz
  8. ├── qux -> ../../qux@1.0.0/node_modules/qux
  9. └── plugh -> ../../plugh@1.0.0/node_modules/plugh
  10. ├── foo@1.0.0_bar@1.0.0+baz@1.1.0
  11. └── node_modules
  12. ├── foo
  13. ├── bar -> ../../bar@1.0.0/node_modules/bar
  14. ├── baz -> ../../baz@1.1.0/node_modules/baz
  15. ├── qux -> ../../qux@1.0.0/node_modules/qux
  16. └── plugh -> ../../plugh@1.0.0/node_modules/plugh
  17. ├── bar@1.0.0
  18. ├── baz@1.0.0
  19. ├── baz@1.1.0
  20. ├── qux@1.0.0
  21. ├── plugh@1.0.0

我们创建 foo@1.0.0_bar@1.0.0+baz@1.0.0foo@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.0b@1.0.0 有一个 peer 依赖为 c@^1a@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。

  1. node_modules
  2. └── .pnpm
  3. ├── a@1.0.0_c@1.0.0
  4. └── node_modules
  5. ├── a
  6. └── b -> ../../b@1.0.0_c@1.0.0/node_modules/b
  7. ├── a@1.0.0_c@1.1.0
  8. └── node_modules
  9. ├── a
  10. └── b -> ../../b@1.0.0_c@1.1.0/node_modules/b
  11. ├── b@1.0.0_c@1.0.0
  12. └── node_modules
  13. ├── b
  14. └── c -> ../../c@1.0.0/node_modules/c
  15. ├── b@1.0.0_c@1.1.0
  16. └── node_modules
  17. ├── b
  18. └── c -> ../../c@1.1.0/node_modules/c
  19. ├── c@1.0.0
  20. ├── c@1.1.0