Плоская структура node_modules не является единственным способом
Новые пользователи pnpm часто спрашивают меня о странной структуре node_modules
которую создает pnpm. Почему она не плоская? Где находятся все под-зависимости?
Предположу, что читатели этой статьи уже знакомы с плоской по структуре папкой
node_modules
, создаваемой npm и Yarn. Если вы не понимаете, почему в npm начиная с третьей версии начали использовать плоскую структуруnode_modules
, вы можете найти некоторую предысторию в Почему мы должны использовать pnpm?.
Так чем же необычна папка node_modules
в pnpm? Давайте создадим две директории и запустим 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
, вы можете спросить?
Here: 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
! The second trick of pnpm's node_modules
structure is that the dependencies of packages are on the same directory level as the real location of the dependent package. Так что зависимости от 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
- пакеты хорошо сгруппированы с их зависимостями
Структура немного сложнее для пакетов с одноранговыми зависимостями, но идея та же: использование символических ссылок для создания вложенности с плоской структурой директорий.