Como os pares são resolvidos
Um dos melhores recursos do pnpm é que em um projeto, uma versão específica de um pacote sempre terá um conjunto de dependências. There is one exception from this rule, though - packages with peer dependencies.
As dependências de peer são resolvidas a partir de dependências instaladas mais acima no gráfico de dependência, pois compartilham a mesma versão que seu pai. That means
that if [email protected]
has two peers (bar@^1
and baz@^1
) then it might have
multiple different sets of dependencies in the same project.
- foo-parent-1
- [email protected]
- [email protected]
- [email protected]
- foo-parent-2
- [email protected]
- [email protected]
- [email protected]
In the example above, [email protected]
is installed for foo-parent-1
and
foo-parent-2
. Both packages have bar
and baz
as well, but they depend on
different versions of baz
. As a result, [email protected]
has two different sets of
dependencies: one with [email protected]
and the other one with [email protected]
. To
support these use cases, pnpm has to hard link [email protected]
as many times as
there are different dependency sets.
Normally, if a package does not have peer dependencies, it is hard linked to a
node_modules
folder next to symlinks of its dependencies, like so:
node_modules
└── .pnpm
├── [email protected]
│ └── node_modules
│ ├── foo
│ ├── qux -> ../../[email protected]/node_modules/qux
│ └── plugh -> ../../[email protected]/node_modules/plugh
├── [email protected]
├── [email protected]
However, if foo
has peer dependencies, there may be multiple sets of
dependencies for it, so we create different sets for different peer dependency
resolutions:
node_modules
└── .pnpm
├── [email protected][email protected][email protected]
│ └── node_modules
│ ├── foo
│ ├── bar -> ../../[email protected]/node_modules/bar
│ ├── baz -> ../../[email protected]/node_modules/baz
│ ├── qux -> ../../[email protected]/node_modules/qux
│ └── plugh -> ../../[email protected]/node_modules/plugh
├── [email protected][email protected][email protected]
│ └── node_modules
│ ├── foo
│ ├── bar -> ../../[email protected]/node_modules/bar
│ ├── baz -> ../../[email protected]/node_modules/baz
│ ├── qux -> ../../[email protected]/node_modules/qux
│ └── plugh -> ../../[email protected]/node_modules/plugh
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
We create symlinks either to the foo
that is inside
[email protected][email protected][email protected]
or to the one in
[email protected][email protected][email protected]
.
Como consequência, o resolvedor do módulo Node.js encontrará os pares corretos.
If a package has no peer dependencies but has dependencies with peers that are
resolved higher in the graph, then that transitive package can appear in the
project with different sets of dependencies. For instance, there's package
[email protected]
with a single dependency [email protected]
. [email protected]
has a peer dependency
c@^1
. [email protected]
will never resolve the peers of [email protected]
, so it becomes
dependent from the peers of [email protected]
as well.
Here's how that structure will look in node_modules
. In this example,
[email protected]
will need to appear twice in the project's node_modules
- resolved
once with [email protected]
and again with [email protected]
.
node_modules
└── .pnpm
├── [email protected][email protected]
│ └── node_modules
│ ├── a
│ └── b -> ../../[email protected][email protected]/node_modules/b
├── [email protected][email protected]
│ └── node_modules
│ ├── a
│ └── b -> ../../[email protected][email protected]/node_modules/b
├── [email protected][email protected]
│ └── node_modules
│ ├── b
│ └── c -> ../../[email protected]/node_modules/c
├── [email protected][email protected]
│ └── node_modules
│ ├── b
│ └── c -> ../../[email protected]/node_modules/c
├── [email protected]
├── [email protected]