Текст и данные · Инструкция
yarn dedupe: как убрать дубликаты зависимостей
`yarn dedupe` помогает убрать исторически накопившиеся совместимые разрешения одной зависимости из lockfile.
Короткий ответ
`yarn dedupe` ищет перекрывающиеся диапазоны зависимостей в lockfile и пытается заменить несколько совместимых разрешённых версий одной. Сначала безопаснее запустить `yarn dedupe --check`: команда ничего не сохраняет и возвращает ненулевой код, если найдены кандидаты на дедупликацию.
Зачем дедуплицировать yarn.lock и что команда реально меняет
В одном Yarn-проекте разные пакеты могут запросить совместимые диапазоны одной библиотеки, но lockfile со временем сохраняет несколько фактически установленных версий. Это увеличивает install footprint, усложняет анализ и иногда создаёт ситуацию, когда одинаковый код существует в двух экземплярах. `yarn dedupe` анализирует такие пересечения и выбирает более общий разрешённый вариант там, где constraints диапазонов это позволяют. По официальной документации текущая стратегия `highest` предпочитает наивысшую подходящую версию. Это не означает, что команда «удалит все дубликаты»: несовместимые диапазоны, разные major-линии и peer dependency контекст могут законно оставить несколько версий.
Важно: Dedupe работает с разрешёнными версиями в lockfile, а не переписывает вашу архитектуру зависимостей. Если manifests требуют несовместимые диапазоны, сначала решается именно этот конфликт.
Безопасный порядок запуска yarn dedupe
- Начните с чистой рабочей директории и убедитесь, что текущий `yarn.lock` закоммичен. Тогда весь эффект команды будет виден в одном diff.
- Запустите `yarn dedupe --check`. По документации Yarn этот режим не сохраняет изменения и возвращает код 1, если проект можно дедуплицировать — это удобно для CI.
- Если кандидаты ожидаемы, выполните обычный `yarn dedupe`. Не объединяйте в тот же коммит ручное обновление десятков dependency ranges, иначе review lockfile станет значительно сложнее.
- Просмотрите diff `yarn.lock`: какие пакеты перешли на другую разрешённую версию, какие записи исчезли и не произошло ли неожиданного подъёма внутри разрешённого диапазона.
- Запустите install/check, unit tests и те интеграционные тесты, которые чувствительны к зависимостям. Стратегия highest может выбрать более новую версию, поэтому изменение нельзя считать чисто косметическим.
- После успешной проверки можно добавить `yarn dedupe --check` в CI, чтобы новые совместимые дубликаты не накапливались незаметно.
Совет: Если diff lockfile очень большой, дедуплицируйте ограниченную зависимость или набор паттернов и проверяйте изменения частями, а не одним трудно обозримым коммитом.
Почему стратегия highest требует тестов
Разрешённый semver-диапазон означает, что пакет формально допускает несколько версий, но это не математическая гарантия отсутствия регрессии в конкретном приложении. Yarn при стратегии `highest` может заменить старую совместимую запись на более высокую версию, уже встречающуюся или допустимую в графе. Если библиотека соблюдает semver, риск обычно контролируемый, но реальный проект может зависеть от поведения, которое изменилось в patch или minor-релизе. Поэтому правильный workflow — считать dedupe изменением dependency resolution, а не форматированием файла. Чем критичнее пакет, тем важнее прогнать тесты и smoke-сценарии после lockfile diff.
Когда дубль можно убрать, а когда он может остаться
- ^1.4.0 и ^1.6.0, доступна 1.9.0. Одна 1.9.0. Диапазоны пересекаются
- ^1.8.0 и ^2.1.0. Две major-версии. Диапазоны не пересекаются
- Транзитивная зависимость имеет жёсткий exact range. Отдельная запись может сохраниться. Нельзя нарушить требование пакета
- Peer dependency создаёт отдельный контекст. Несколько экземпляров могут быть оправданы. Совместимость зависит не только от номера пакета
Предупреждение: Две версии в lockfile не всегда дефект. Цель — убрать лишние совместимые дубли, а не добиться одной версии любой ценой.
Как использовать --check в CI без автоправок
Для CI лучше разделить обнаружение и изменение. `yarn dedupe --check` подходит для первого: он не должен переписывать репозиторий, но может сделать job красным, если есть работа для dedupe. Такой сигнал позволяет разработчику выполнить команду локально, посмотреть lockfile diff и прислать осмысленный commit. Автоматически запускать изменяющий dedupe прямо в CI и коммитить результат от бота можно, но это усложняет ownership и тестирование. Если проект большой и дубликаты появляются часто, разумнее настроить отдельный maintenance workflow с pull request, где видны изменения и проходит полный pipeline.
Почему dedupe не заменяет обновление dependency ranges
Если два workspace явно требуют разные major-версии, dedupe ничего не должен «исправлять». Нужно решить, можно ли обновить старый пакет, заменить зависимость или оставить две линии до миграции. Аналогично принудительное override ради одной версии может скрыть несовместимость, которую автор зависимости специально выразил диапазоном. Dedupe полезен после обычных установок и обновлений, когда дерево накопило исторически разные, но теперь совместимые разрешения. Для политики единых declared versions в monorepo лучше использовать catalogs или constraints; dedupe находится уже на следующем уровне — уровне lockfile resolution.
Что проверить после дедупликации
- В рабочем дереве изменился в основном `yarn.lock`, а не случайные manifests.
- Удалённые записи действительно покрываются оставшимися semver-диапазонами.
- Не возникли новые peer dependency warnings.
- Проект устанавливается с immutable-настройками так же, как CI.
- Тесты основных приложений и библиотек проходят.
- Размер diff понятен и объясним в pull request.
- При использовании `--check` CI падает только на реально найденных кандидатах, а не из-за другой ошибки команды.
Как отличить полезную дедупликацию от бессмысленной гонки за одной версией
Самая полезная метрика — не число строк в lockfile, а снижение ненужной вариативности без нарушения контрактов зависимостей. Если после dedupe пакет загружается один раз вместо трёх совместимых копий, уменьшается install footprint и проще расследовать баги. Если ради одной версии приходится писать override поверх несовместимого peer range, это уже другая операция с другим риском. Оставляйте обоснованные дубли, документируйте крупные migration blockers и используйте dedupe регулярно, но предсказуемо. Тогда команда остаётся инструментом гигиены lockfile, а не способом силой «починить» любой dependency conflict.
Как дедуплицировать не весь проект, а один пакет
Когда общий `yarn dedupe` создаёт слишком большой lockfile diff, Yarn позволяет передать конкретный ident или glob-паттерн и ограничить область проверки. Например, можно сначала обработать одну проблемную библиотеку, прогнать тесты, а затем перейти к следующей группе. Это особенно удобно после крупной миграции, когда часть дерева намеренно остаётся на старой major-линии. Паттерны следует экранировать так, чтобы их не развернул shell раньше Yarn; официальная документация отдельно предупреждает об этом для glob-аргументов. В CI для всего проекта практичнее оставить `yarn dedupe --check`: он не сохраняет изменения, но возвращает ненулевой статус при найденных дубликатах. Такой режим не смешивает автоматическую правку lockfile с диагностикой и делает причину падения job понятной при review.
Что учитывать
Разрешённый semver-диапазон означает, что пакет формально допускает несколько версий, но это не математическая гарантия отсутствия регрессии в конкретном приложении. Yarn при стратегии `highest` может заменить старую совместимую запись на более высокую версию, уже встречающуюся или допустимую в графе. Если библиотека соблюдает semver, риск обычно контролируемый, но реальный проект может зависеть от поведения, которое изменилось в patch или minor-релизе. Поэтому правильный workflow — считать…
Источники и проверка
Фактическая часть сверена по первичным источникам (в т.ч. yarn dedupe). Пример и формулировки — редакция N1RO на 2026-09-21.