DEV Community

Даниил Пронин
Даниил Пронин

Posted on • Edited on

7 3

Почему не надо коммитить папку node_modules

English | Русский

Эта заметка — ответы на вопросы, которые могут возникнуть при чтении статьи Джека Франклина в переводе For Web.

Нет нужды в npm install

Если вы храните node_modules в git, вам не нужно отдельно устанавливать зависимости, чтобы запустить проект.

  1. 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

  2. Некоторые пакеты зависят от платформы. Например, инструменты для разработки, такие как dart-sass.

  3. Если вы закоммитили 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"
Enter fullscreen mode Exit fullscreen mode

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 весь код, попадающий в проект при их подключении. Это побудило нас поработать над инструментами, помогающими оценить влияние зависимостей на размер бандла и оптимизировать занимаемое на диске место.

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

  • Bundlephobia

    Покажет, сколько весит зависимость, сколько будет с GZIP, как долго она будет скачиваться по медленному 3G и по среднему 4G-интернету, покажет в процентном соотношении состав под-зависимостей, что зависимость экспортирует (если она написана на ES Modules), а также какие у неё есть альтернативы или соседние пакеты. Вот пример.

  • bundlejs.com

    Покажет, сколько точно в килобайтах будет добавлено кода при импорте вроде

    import { map } from "nanostores"
    

    Посмотрите это на примере nanostores.

  • npm.anvaka.com

    Покажет график всех зависимостей в виде 2D или 3D-графика. Посмотрите на примере Vue 3

Более вдумчивое добавление зависимостей, потому что они больше не скрыты

Я уже упоминал, что шум в диффах воспринимается людьми как недостаток хранения зависимостей в git, и я признаю, что это действительно может быть проблемой. Однако для меня этот шум оказался полезным знаком. Раньше я часто подключал новые зависимости, просто потому что не хотел сам писать несколько строчек кода. Теперь же я гораздо внимательнее отношусь к добавлению новых зависимостей, потому что я могу увидеть добавленный ими код и решить, стоит ли он того.

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

Примечание: это не означает, что у нас нет зависимостей! Бывают ситуации, когда подключить зависимость выгодно, но видимость кода в системе контроля версий сделала меня более осознанным — цена добавления зависимостей больше не скрыта.

Она никогда и не была скрыта.

C большими диффами можно справиться

Нельзя игнорировать тот факт, что добавление или обновление зависимостей может вызвать много шума в диффе. Одна из наших зависимостей — TypeScript, и каждое его обновление приносит огромный дифф в git, который, честно говоря, не стоит просмотра (за пределами CHANGELOG). Мы пришли к правилу, которое помогает в таких ситуациях: изменения в node_modules должны быть отделены от любых изменений в основной кодовой базе. Так что если я обновлю node_modules/typescript до свежей версии, наш инструментарий предупредит меня при обнаружении изменений за пределами node_modules.

Вы пришли к костылю.

Это правило помогает нам в большинстве случаев, потому что любая задача, требующая добавления или обновления зависимостей, может быть разделена на две части:

  1. Обновление или добавление зависимости
  2. Использование зависимости в коде

Иногда это не работает: например, обновление TypeScript может потребовать от нас исправления в коде ошибок, которые теперь обнаруживает новая версия TypeScript. В таких случаях мы отменяем правило.

И вот последствия хождения на костылях.

Защита от очередного left_pad

Печально известный инцидент с left_pad (популярный npm-пакет был внезапно удалён, ломая сборки проектов по всему миру) не затронул бы команду, которая хранит зависимости в git. В долгосрочной перспективе команде всё ещё пришлось бы разбираться с вопросом «что теперь делать с более не поддерживаемой зависимостью», но в краткосрочной перспективе их сборки бы не сломались, а релизы бы не были заблокированы.

Я помню тот день, когда left_pad был удалён с NPM. Я тогда работал в digital-агентстве на потоке сайтов, и, конечно же, во всех проектах, за которые я был ответственен, left_pad был под-зависимостью. Мы решили эту проблему тогда примерно за полчаса, когда CI показал 404 при попытке скачать пакет. Я уже не помню, что именно мы предприняли, но такая задача не должна быть вызовом и поводом городить костыли.

В конце концов, для защиты от именно таких проблем, вы можете поднять у себя прокси-реестр, например, с помощью Verdaccio. Он будет хранить у себя все копии всех скачанных пакетов.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (1)

Collapse
 
grawl profile image
Даниил Пронин

скопировал эту заметку из своего gist gist.github.com/Grawl/2bfce69521ae...

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay