Нові користувачі pnpm часто запитують мене про дивну структуру node_modules
, яку створює pnpm. Чому вона не плоска? Куди поділись усі залежності (sub-dependency)?
Я припускаю, що читачі статті вже знайомі з плоскими
node_modules
, створеними npm і Yarn. Якщо ви не розумієте, чому npm 3 повинен був почати використовувати flatnode_modules
у версії 3, ви можете знайти деякі передісторії в Чому ми повинні використовувати pnpm?.
Отже, чому pnpm node_modules
незвичний? Створімо дві директорії та запустимо npm add express
в одній з них і pnpm add express
в іншій. Ось верхня частина того, що ви отримуєте в першій директорії node_modules
:
.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express
Ви можете переглянути всю директорію тут.
І ось що ви отримуєте в node_modules
, створених pnpm:
.pnpm
.modules.yaml
express
Ви можете перевірити її тут.
Тож де всі залежності? Існує лише одна тека в node_modules
під назвою .pnpm
та символьне посилання на express
. Що ж, ми встановили лише express
, тож це єдиний пакет, до якого ваша програма має мати доступ
Докладніше про те, чому строгість pnpm — це добре тут
Подивимося, що всередині express
:
▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml
express
не має node_modules
? Де всі залежності express
-су?
Фокус у тому, що Express
— це просто символьне посилання. Коли Node.js вирішує залежності, він використовує їх реальне розташування, тому він не зберігає символічні посилання. Але де ж насправді знаходиться express
, запитаєте ви?
Тут: node_modules/.pnpm/express@4.17.1/node_modules/express.
Добре, тепер ми знаємо призначення папки .pnpm/
. .pnpm/
зберігає всі пакунки в плоскій структурі папок, тому кожен пакунок можна знайти в папці, названій за цим шаблоном:
.pnpm/<name>@<version>/node_modules/<name>
Ми називаємо його каталогом віртуального сховища.
Ця плоска структура дозволяє уникнути проблем з довгим шляхом, які були спричинені вкладеними node_modules
, створеними npm v2, але зберігає пакети ізольованими на відміну від плоских node_modules
, створених npm v3,4,5,6 або Yarn v1.
Тепер давайте подивимося на справжнє місце розташування express
:
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
Це шахрайство? Йому все ще бракує node_modules
! Друга хитрість структури pnpm node_modules
полягає в тому, що залежності пакетів знаходяться на тому самому рівні каталогу, на якому знаходиться справжнє розташування залежного пакета. Отже, залежності express
знаходяться не в .pnpm/express@4.17.1/node_modules/express/node_modules/
, а в .pnpm/express@4.17.1/node_modules/:
▾ node_modules
▾ .pnpm
▸ accepts@1.3.5
▸ array-flatten@1.1.1
...
▾ express@4.16.3
▾ node_modules
▸ accepts
▸ array-flatten
▸ body-parser
▸ content-disposition
...
▸ etag
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
Усі залежності express
є символьними посиланнями на відповідні каталоги в node_modules/.pnpm/
. Розміщення залежностей Express
на один рівень вище дозволяє уникнути циклічних символьних посилань.
Отже, як ви бачите, попри те, що структура pnpm node_modules
спочатку виглядає незвичною:
- повністю сумісна з Node.js
- пакети добре згрупованні з їх залежностями
Структура трохи складніша для пакунків з одноранговими залежностями, але ідея та сама: використання символьних посилань для створення вкладеності з плоскою структурою каталогів.