lenec ru

← все посты

ERR_PNPM_PEER_DEP_ISSUES: как починить и не сломать lockfile

13K

Сообщение ERR_PNPM_PEER_DEP_ISSUES от pnpm пугает многих. Текст длинный, в красном цвете, со списком пакетов, которые «должны быть, но их нет» или «должны быть другой версии, чем у тебя установлена». Разбираю, что это значит и как чинить, не превращая package.json в кашу.

Что вообще такое peer dependency

Peer dependency — это «я хочу, чтобы вместе со мной у тебя был установлен такой-то пакет такой-то версии, но я не буду тащить его сам». Классический пример — плагин для React: react-foo объявляет peerDependency: react ^18, и значит «приложение должно само поставить React 18, я не дублирую».

В npm peer dependency раньше игнорировались, потом стали авто-устанавливаться. В pnpm же поведение по умолчанию строгое: если peer dep не удовлетворён, pnpm пишет о проблеме.

Как выглядит ошибка

ERR_PNPM_PEER_DEP_ISSUES  Unmet peer dependencies

.
├─┬ react-query
│ └── ✕ unmet peer react@"^17.0.0": found 18.2.0
└─┬ next-themes
  └── ✕ missing peer react-dom@"^17.0.0"

Что pnpm говорит:

  • react-query хочет React 17, а у тебя 18. Несовпадение версий.
  • next-themes хочет react-dom 17, а его нет в зависимостях вовсе.

Когда это критично, а когда нет

Не каждый peer-conflict — реальная проблема. Часто пакет работает с более новой версией, просто не успели обновить ограничение.

  • Реальная проблема: пакет упадёт в рантайме или будет работать с багами.
  • Шум: пакет работает прекрасно, peer-ограничение устарело и автор не выпустил релиз.

Ты узнаёшь, что именно у тебя, только проверив. Я обычно начинаю с issue-трекера пакета: «works with react 18?» — и почти всегда видно, что да, всё ок.

Способы починки

1. Установить недостающий peer

Если пакет реально хочет react-dom, и ты его забыл — поставь:

pnpm add react-dom@^18

Базово помогает в случае «missing peer». pnpm увидит, что пакет теперь есть, и предупреждение исчезнет.

2. Обновить пакет, у которого устарело peer-ограничение

pnpm update react-query --latest

Если автор уже выпустил релиз с поддержкой React 18 — обновление снимает проблему. Не забудь прочитать changelog и проверить тесты.

3. peerDependencyRules: ignoreMissing

Если ты точно знаешь, что peer dep не нужен — попроси pnpm не ругаться. В корне проекта в package.json:

{
  "pnpm": {
    "peerDependencyRules": {
      "ignoreMissing": ["some-optional-peer"]
    }
  }
}

Использую только в крайнем случае, когда я уверен в отсутствии последствий.

4. peerDependencyRules: allowedVersions

Когда пакет работает с более новой версией, но автор пока не обновил ограничение:

{
  "pnpm": {
    "peerDependencyRules": {
      "allowedVersions": {
        "react": "18",
        "react-dom": "18"
      }
    }
  }
}

pnpm перестанет ругаться на конфликт, считая, что 18 ок для тех пакетов, которые требуют 17. Удобно для библиотек, которые отстали от своих peer-ограничений.

5. overrides

Если какой-то пакет тащит зависимость с известным багом, и ты хочешь форсировать другую версию:

{
  "pnpm": {
    "overrides": {
      "some-buggy-package": "^2.5.0",
      "another-package>some-buggy-package": "^2.5.0"
    }
  }
}

Первая запись применяется ко всем употреблениям пакета, вторая — только к транзитивной зависимости конкретного родителя. Используй точечно: проще наделать дыр в дереве зависимостей, чем починить.

6. auto-install-peers

В .npmrc можно включить автоустановку peer dep:

auto-install-peers=true

pnpm сам тащит peer dep при install. С одной стороны, удобно. С другой — добавляет в lockfile зависимости, которые ты явно не объявлял. На больших командах я бы оставил false и ставил peer dep вручную.

Реальный пример из работы

На одном проекте после апгрейда Next.js на 14 я ловил такой набор:

react@18.3.1
  ✕ unmet peer react@"^17.0.0" needed by react-helmet-async
  ✕ unmet peer react@"^17.0.0" needed by react-virtuoso

Что я сделал:

  1. Открыл changelog react-virtuoso: с версии 4.x у них уже React 18 поддерживается. Сделал pnpm add react-virtuoso@^4. Перешло.
  2. react-helmet-async уже не обновляется. Я заменил его на встроенный next/head, проблема ушла как класс.

Никаких peerDependencyRules не понадобилось. Реальный анализ почти всегда выгоднее, чем «давай заглушим warning».

Когда warning — это просто шум

Бывает, что peer-conflict живёт годами, потому что пакет не обновляется. Если код работает, тесты зелёные, jq на CI ок — это шум. Тогда я в peerDependencyRules.allowedVersions явно прописываю «знаю, всё ок» и иду дальше.

Главное — не отключать предупреждения глобально. Каждое исключение должно быть подписано в комментарии git, чтобы потом не разбираться, зачем у тебя в pnpm-конфиге странный override.

strictPeerDependencies

Если у тебя в проекте включён строгий режим:

strict-peer-dependencies=true

pnpm не просто warn-ит, а падает на install. Это полезно для библиотек, которые публикуются и должны иметь чистое дерево зависимостей. Для приложений я обычно оставляю warning-режим.

Lockfile

Любые изменения зависимостей коммить с lockfile-ом. pnpm-lock.yaml в git, всегда. Без него на CI ты получишь другие версии транзитивных зависимостей и можешь поймать совсем другие peer-проблемы.

Что делать с workspaces

На монорепе с workspaces peer-dep живёт отдельно у каждого пакета. Если ты ставишь зависимость в один пакет, peer-dep этого пакета может конфликтовать с тем, что есть в другом. pnpm в таком случае иногда поднимает дубли, иногда говорит о проблеме.

Правило: общие зависимости (react, типы) лучше держать в корне через shared-workspace или с одинаковыми ограничениями в каждом пакете. Иначе ловишь странные проблемы.

Шпаргалка

  • Прочитай ошибку: missing или unmet?
  • Missing — поставь peer-пакет.
  • Unmet с устаревшим ограничением — обнови сам пакет, либо allowedVersions.
  • Реально несовместимая версия — ищи альтернативу.
  • Никогда не отключай предупреждения целиком.

peer-dep ошибки выглядят страшно, но 9 из 10 чинятся за пару минут. Главное — не пытаться обмануть pnpm, а действительно разобраться, почему пакеты не сходятся. Это занимает чуть больше времени один раз, но экономит часы дальнейшего дебага.

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.