Текст и данные · Инструкция
pnpm dedupe: как убрать дубликаты зависимостей
pnpm dedupe полезен, когда lockfile накопил несколько совместимых версий одной зависимости после обновлений разных.
Короткий ответ
Как безопасно запустить pnpm dedupe и --check, ограничить workspace фильтром, проверить diff lockfile и понять, почему две версии могут остаться.
Что именно делает pnpm dedupe и чего от него не ждать
Команда анализирует разрешённые версии и пытается заменить более старые записи на более новые там, где ограничения зависимостей это допускают. Результат отражается прежде всего в lockfile и последующей установке. Если один пакет требует диапазон, совместимый с версией 3.4, а другой допускает ту же 3.4, отдельная старая 3.2 может оказаться лишней. Но если диапазоны не пересекаются или peer dependency требует другую комбинацию, две версии могут остаться обоснованно. Поэтому количество одинаковых имён в store или дереве не является самостоятельным признаком ошибки; важнее, можно ли их безопасно схлопнуть по правилам resolver.
Предупреждение: Не удаляйте pnpm-lock.yaml ради «чистой» установки: это меняет весь граф разрешений и решает совсем другую задачу.
Безопасная последовательность: check, dedupe, diff, tests
- Зафиксируйте чистое состояние Git: Перед операцией убедитесь, что `git status` не смешивает дедупликацию с посторонними изменениями.
- Запустите `pnpm dedupe --check`: Команда проверит, возможны ли изменения, без установки пакетов и правки lockfile. В CI ненулевой код можно использовать как сигнал.
- Выполните `pnpm dedupe`: Если изменения ожидаемы, запустите обычную команду из корня нужного проекта или workspace.
- Просмотрите diff lockfile: Проверьте, какие версии исчезли и какие записи были переиспользованы. Большой неожиданный diff лучше расследовать до коммита.
- Переустановите в чистой среде: В CI или временном каталоге выполните обычную воспроизводимую установку проекта.
- Запустите тесты и сборку: Особенно важны тесты пакетов с peer dependencies, нативными модулями и инструментами сборки.
Совет: `pnpm dedupe --check` особенно удобен как отдельный CI-gate: он не модифицирует репозиторий, а только сообщает, есть ли возможная дедупликация.
Как команда ведёт себя в workspace и зачем нужен --filter
Начиная с pnpm 12.4.1, официальная документация указывает, что `pnpm dedupe` по умолчанию обрабатывает каждый проект workspace, включая конфигурации с lockfile на проект. В большом monorepo это важно: запуск из корня может затронуть больше пакетов, чем ожидал разработчик. Для локальной работы используйте обычные фильтры pnpm, например `pnpm dedupe --filter ./packages/app`. Если фильтр формируется скриптом и отсутствие совпадений должно считаться ошибкой, пригодится `--fail-if-no-match`. Такой подход делает область изменений явной и уменьшает случайный шум в pull request.
Важно: После обновления pnpm перепроверьте поведение workspace-команд: оно может меняться между major/minor версиями, а CI должен быть привязан к версии package manager.
Когда использовать dedupe, а когда другой инструмент
- Lockfile накопил совместимые старые версии. `pnpm dedupe`. Команда специально оптимизирует разрешённые версии
- Нужно только узнать, возможны ли изменения. `pnpm dedupe --check`. Проверяет без установки и записи lockfile
- Нужно удалить неиспользуемые пакеты проекта. Проверить зависимости/`pnpm prune` по задаче. Это не дедупликация версий
- Нужно очистить глобальный content-addressable store. `pnpm store prune`. Store — другая область и другой интент
- Нужно заставить транзитивную зависимость иметь конкретную версию. Рассмотреть overrides. Это политика разрешения, а не обычный dedupe
Почему после дедупликации всё равно могут остаться две версии
Самая частая ложная тревога — ожидание, что любое повторяющееся имя пакета обязано стать единственной версией. Пакет A может требовать `^1`, пакет B — `^2`; объединить их невозможно без изменения требований. Отдельные peer dependency контексты тоже способны создавать разные снимки одного пакета, потому что окружение peers является частью совместимости. Нативные зависимости иногда различаются по платформе или optional-наборам. Поэтому после `dedupe` сначала смотрят, какие constraints удерживают версии. Для расследования используйте команды просмотра дерева и объяснения зависимостей, а не ручное редактирование YAML lockfile.
Минимальная проверка перед коммитом результата
- `git diff -- pnpm-lock.yaml` понятен и соответствует задаче.
- Версия pnpm в локальной среде совпадает с версией CI/`packageManager`.
- Повторная установка на чистом checkout проходит без изменения lockfile.
- Unit/integration tests зелёные.
- Сборка всех затронутых workspace-пакетов проходит.
- Нет неожиданных изменений manifest-файлов.
- Если использован `--filter`, он действительно выбрал нужный проект.
Важно: Не принимайте огромный lockfile diff вслепую. Дедупликация должна быть отдельным понятным изменением, чтобы её можно было откатить и проверить.
Как встроить дедупликацию в командную разработку
Для небольшого проекта достаточно периодического ручного запуска после серии обновлений. В monorepo полезнее разделить проверку и изменение: CI выполняет `pnpm dedupe --check` и сигнализирует о возможной оптимизации, а сам `pnpm dedupe` запускается в отдельном pull request. Так reviewer видит только изменения графа зависимостей, а не смесь с функциональным кодом. Не стоит запускать автоматический dedupe в каждом install и незаметно коммитить результат ботом без тестов: lockfile — часть воспроизводимости сборки. Лучше закрепить версию pnpm, запускать тесты на том же lockfile и документировать, почему изменение дерева безопасно.
Как оценивать эффект dedupe без иллюзии по размеру node_modules
В pnpm физическая организация пакетов отличается от классического плоского `node_modules`, поэтому экономию нельзя оценивать только числом папок в проводнике. Content-addressable store переиспользует содержимое, а проектные ссылки отражают разрешённый граф. Полезнее смотреть на изменение lockfile, число реально разных версий, время install и размер deploy-артефакта в вашем workflow. Если цель — уменьшить Docker image, после dedupe всё равно проверьте, какие файлы копируются в финальный слой. Иногда главный объём создают build artifacts, cache или devDependencies, и дедупликация почти не влияет на конечный образ.
Что учитывать
Самая частая ложная тревога — ожидание, что любое повторяющееся имя пакета обязано стать единственной версией. Пакет A может требовать `^1`, пакет B — `^2`; объединить их невозможно без изменения требований. Отдельные peer dependency контексты тоже способны создавать разные снимки одного пакета, потому что окружение peers является частью совместимости. Нативные зависимости иногда различаются по платформе или optional-наборам. Поэтому после `dedupe` сначала смотрят, какие constraints удерживают…
Источники и проверка
Фактическая часть сверена по первичным источникам (в т.ч. pnpm dedupe). Пример и формулировки — редакция N1RO на 2026-09-20.