Як вирішуються конфлікти прямих залежностей
Однією з найкращих особливостей pnpm є те, що в одному проєкті певна версія пакунка завжди матиме один набір залежностей. There is one exception from this rule, though - packages with peer dependencies.
Прямі залежності вирішуються і з залежностей, встановлених вище на графі залежностей, оскільки вони мають ту саму версію, що й їхні батьки. Це означає, що якщо foo@1.0.0
має дві прямі залежності (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
. Обидва пакунки також мають bar
та baz
, але вони залежать від різних версій baz
. Як наслідок, foo@1.0.0
має два різних набори залежностей: один з baz@1.0.0
, а інший з baz@1.1.0
. Для підтримки цих варіантів використання pnpm має створити жорстке посилання foo@1.0.0
стільки разів, скільки існує різних наборів залежностей.
Зазвичай, якщо пакунок не має прямих залежностей, він привʼязується до теки 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
має прямі залежності, для нього може існувати декілька наборів залежностей, тому ми створюємо різні набори для різних резолюцій прямих залежностей:
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
, що знаходиться всередині foo@1.0.0_bar@1.0.0+baz@1.0.0
, або на той, що знаходиться в foo@1.0.0_bar@1.0.0+baz@1.1.0
. Як наслідок, модуль Node.js знайде правильні прямі залежності.
Якщо пакунок не має залежностей від однорангових пакунків, але має залежності від однорангових пакунків, що розташовані вище на графі, то цей транзитивний пакунок може зʼявитися у проєкті з різними наборами залежностей. Наприклад, є пакунок a@1.0.0
з єдиною залежністю b@1.0.0
. b@1.0.0
має пряму залежність c@^1
. a@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