Перейти к основному содержимому

Плоская структура node_modules не является единственным способом

· 3 мин. читать

Новые пользователи 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 структура кажется необычной поначалу:

  1. она полностью совместима с Node.js
  2. пакеты хорошо сгруппированы с их зависимостями

Структура немного сложнее для пакетов с одноранговыми зависимостями, но идея та же: использование символических ссылок для создания вложенности с плоской структурой директорий.