Как одна команда запускает цепочку установок

JavaScript-пакет обычно описывает свои зависимости в манифесте — файле с перечнем модулей, нужных ему для работы. Когда разработчик устанавливает фреймворк, менеджер пакетов читает этот список, затем открывает манифесты уже названных модулей и проверяет их требования. Так установка проходит по цепочке: библиотека может опираться на другие библиотеки, а те — на следующие.

Эта структура называется графом зависимостей. Небольшое приложение использует лишь часть возможностей фреймворка, но установка часто приносит весь набор модулей, от которого тот зависит. Поэтому простая стартовая программа не означает простой состав проекта.

Почему каталогов становится так много

Каждый модуль хранится в файловой системе как отдельный пакет. При этом двум частям проекта могут понадобиться разные версии одной библиотеки: если совместить их нельзя, менеджер пакетов способен разместить обе. Некоторые пакеты также зависят от крупных инструментов, нужных не самому приложению во время работы, а для сборки или проверки кода.

В результате в проекте появляются вложенные каталоги `node_modules`, а иногда и повторяющиеся пакеты. Число папок не равно числу функций, которыми пользуется приложение: это след установленной цепочки требований, а не перечень всего, что программа вызывает напрямую.

Что помогает управлять этой сложностью

Файл блокировки фиксирует выбранные версии пакетов и их связей. Благодаря ему другая установка может воспроизвести тот же набор зависимостей, а не заново подобрать допустимые версии. Перед обновлением разработчики проверяют, не изменится ли поведение приложения, поскольку новая версия одного модуля может затронуть другие части цепочки.

Именно поэтому «Hello World» способен начинаться с одного короткого файла, но занимать заметное место на диске: код приложения мал, а вместе с ним устанавливается инфраструктура, которую оно наследует через фреймворк.