Почему важно, чтобы у всех разработчиков были одинаковые версии зависимостей
Что проверяют
Понимаете ли вы, чем package.json отличается от lock-файла, и что стоит за фразой «у меня локально работает». Это вопрос про воспроизводимость сборки, а не про аккуратность разработчика.
Как отвечать
В манифесте записан диапазон, а не версия: ^1.2.3 разрешает любой выпуск до смены мажорного номера. Два человека, установившие зависимости с разницей в неделю, получат разные деревья, и касается это в первую очередь транзитивных пакетов, которые никто не выбирал руками.
Lock-файл фиксирует дерево целиком: точные версии, адреса и хеши целостности. Он коммитится, а на сборочной машине зависимости ставятся через npm ci, который собирает строго по локу и падает, если лок разошёлся с манифестом. Обычный npm install в конвейере недопустим: он молча правит лок.
Что ломается, когда версии разъехались:
- баг воспроизводится у одного человека и не воспроизводится у остальных, а время уходит на поиски в собственном коде;
- в дереве оказываются две копии библиотеки, и всё, что требует единственного экземпляра, перестаёт работать: хуки React, контексты, инициализация библиотеки локализации;
- на прод уезжает не то, что тестировали, потому что сборка начиналась с чистой установки.
Картину дополняют фиксация версии Node через .nvmrc или поле engines и обновление зависимостей отдельным осознанным изменением, а не попутно с фичей.
Где спотыкаются
Удаляют lock-файл при конфликте слияния и ставят зависимости заново. Конфликт исчезает, но вместе с ним исчезает и всё зафиксированное дерево. Правильный путь: взять лок из основной ветки и доустановить нужный пакет поверх него.
Верят, что диапазон безопасен, раз семантическое версионирование обещает совместимость. Обещание соблюдают не все, и патч-выпуск где-то в глубине дерева ломает сборку регулярно.
Прописывают точные версии прямо в манифесте и на этом успокаиваются. Транзитивные зависимости всё равно остаются диапазонами, так что без лока дерево продолжает плавать от установки к установке.