English | Русский
Эта заметка — ответы на вопросы, которые могут возникнуть при чтении статьи Джека Франклина в переводе For Web.
Если вы храните
node_modules
в git, вам не нужно отдельно устанавливать зависимости, чтобы запустить проект.
-
git плохо работает с большим количеством файлов в репозитории. Поиск фразой “git performance many files” показывает много полезной информации об этом. Например, вот: Just as git does not scale well with large files, it can also become painful to work with when you have a large number of files
-
Некоторые пакеты зависят от платформы. Например, инструменты для разработки, такие как
dart-sass
. -
Если вы закоммитили
node_modules
, это значит, что у любого разработчика теперь есть лёгкий способ что-либо исправить в любой из зависимостей (это называется “monkey patching”), и это определённо точно приведёт к тому, что после обновления этой “исправленной” зависимости прошлое исправление будет перетёрто, и с этой проблемой придётся как-то разбираться. Вы вообще не будете уверены в том, что зависимость определённой версии соответствует тому виду, в котором она была изначально получена.
Это полезно не только для локальной разработки, но и для ботов на CI-платформах: они могут полностью пропустить шаг установки зависимостей.
CI обычно настраивают так, чтобы зависимости кешировались, и не устанавливались каждый раз с нуля. Гуглить фразой “ci node_modules cache”.
Хранение
node_modules
в git гарантирует, что два разработчика запускают один и тот же код с одним и тем же набором зависимостей.
Эту проблему решает “лок-файл” — специальный файл, который нужно коммитить, в который пакетный менеджер (NPM/PNPM/Yarn) записывает о каждой скачанной зависимости все необходимые данные для гарантии воспроизводимой сборки.
Если заглянуть в yarn.lock
, можно увидеть следующее:
"@apideck/better-ajv-errors@^0.2.4":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.2.5.tgz#b9c0092b7f7f23c356a0a31600334f7b8958458b"
integrity sha512-Pm1fAqCT8OEfBVLddU3fWZ/URWpGGhkvlsBIgn9Y2jJlcNumo0gNzPsQswDJTiA8HcKpCjOhWQOgkA9kXR4Ghg==
dependencies:
json-schema "^0.3.0"
jsonpointer "^4.1.0"
leven "^3.1.0"
Yarn заботливо записал, что он скачал пакет @apideck/better-ajv-errors
:
- версии
0.2.5
- по адресу
resolved
(прямая ссылка на.tgz
) - хеш-сумма файла была
sha512-Pm1fAqCT8OE...
- и у этого пакета было 3 зависимости
И так для каждой зависимости, размещённой в папке node_modules
. И в следующий раз, когда в папке проекта будет запущена команда yarn install
, зависимости будут скачаны не тех версий, что указаны в package.json
, а те, что записаны в yarn.lock
. Следовательно, у всей команды и на CI независимо от платформы (Linux/macOS/Windows) будет один и тот же набор файлов, один и тот же код, с одними и теми же хеш-суммами.
Да, этого можно добиться, используя локфайлы или другие инструменты, однако я встречал случаи, когда они не спасали от изменения минорной версии какой-либо зависимости.
Эту ошибку часто допускают, когда при развёртывании проекта у разработчика запускается npm install
, который устанавливает пакеты по информации из package.json
, а не package-lock.json
. Чтобы установить пакеты из лок-файла, нужно запускать npm ci
.
Я был удивлён тем, насколько я стал осведомлённее касательно зависимостей, когда стал видеть в диффе git весь код, попадающий в проект при их подключении. Это побудило нас поработать над инструментами, помогающими оценить влияние зависимостей на размер бандла и оптимизировать занимаемое на диске место.
При выборе зависимостей можно пользоваться специальными инструментами, а не просто читать километры кода.
-
Покажет, сколько весит зависимость, сколько будет с GZIP, как долго она будет скачиваться по медленному 3G и по среднему 4G-интернету, покажет в процентном соотношении состав под-зависимостей, что зависимость экспортирует (если она написана на ES Modules), а также какие у неё есть альтернативы или соседние пакеты. Вот пример.
-
Покажет, сколько точно в килобайтах будет добавлено кода при импорте вроде
import { map } from "nanostores"
-
Покажет график всех зависимостей в виде 2D или 3D-графика. Посмотрите на примере Vue 3
Я уже упоминал, что шум в диффах воспринимается людьми как недостаток хранения зависимостей в git, и я признаю, что это действительно может быть проблемой. Однако для меня этот шум оказался полезным знаком. Раньше я часто подключал новые зависимости, просто потому что не хотел сам писать несколько строчек кода. Теперь же я гораздо внимательнее отношусь к добавлению новых зависимостей, потому что я могу увидеть добавленный ими код и решить, стоит ли он того.
Вы можете прочитать код и до того, как добавить зависимость в проект. Например, зайдя в репозиторий на GitHub. Крайне советую хотя бы мельком смотреть зависимости, адекватность кода, количество открытых issue и дату последнего коммита.
Примечание: это не означает, что у нас нет зависимостей! Бывают ситуации, когда подключить зависимость выгодно, но видимость кода в системе контроля версий сделала меня более осознанным — цена добавления зависимостей больше не скрыта.
Она никогда и не была скрыта.
Нельзя игнорировать тот факт, что добавление или обновление зависимостей может вызвать много шума в диффе. Одна из наших зависимостей — TypeScript, и каждое его обновление приносит огромный дифф в git, который, честно говоря, не стоит просмотра (за пределами CHANGELOG). Мы пришли к правилу, которое помогает в таких ситуациях: изменения в
node_modules
должны быть отделены от любых изменений в основной кодовой базе. Так что если я обновлюnode_modules/typescript
до свежей версии, наш инструментарий предупредит меня при обнаружении изменений за пределамиnode_modules
.
Вы пришли к костылю.
Это правило помогает нам в большинстве случаев, потому что любая задача, требующая добавления или обновления зависимостей, может быть разделена на две части:
- Обновление или добавление зависимости
- Использование зависимости в коде
Иногда это не работает: например, обновление TypeScript может потребовать от нас исправления в коде ошибок, которые теперь обнаруживает новая версия TypeScript. В таких случаях мы отменяем правило.
И вот последствия хождения на костылях.
Печально известный инцидент с left_pad (популярный npm-пакет был внезапно удалён, ломая сборки проектов по всему миру) не затронул бы команду, которая хранит зависимости в git. В долгосрочной перспективе команде всё ещё пришлось бы разбираться с вопросом «что теперь делать с более не поддерживаемой зависимостью», но в краткосрочной перспективе их сборки бы не сломались, а релизы бы не были заблокированы.
Я помню тот день, когда left_pad
был удалён с NPM. Я тогда работал в digital-агентстве на потоке сайтов, и, конечно же, во всех проектах, за которые я был ответственен, left_pad
был под-зависимостью. Мы решили эту проблему тогда примерно за полчаса, когда CI показал 404 при попытке скачать пакет. Я уже не помню, что именно мы предприняли, но такая задача не должна быть вызовом и поводом городить костыли.
В конце концов, для защиты от именно таких проблем, вы можете поднять у себя прокси-реестр, например, с помощью Verdaccio. Он будет хранить у себя все копии всех скачанных пакетов.
скопировал эту заметку на https://dev.to/grawl/pochiemu-nie-nado-kommitit-papku-nodemodules-e37