n1ro°
RU

Ошибки и коды · Инструкция

Yarn PnP: нет node_modules — как настроить совместимость

Yarn PnP может работать без `node_modules`: при Plug'n'Play зависимости разрешаются через загрузчик `.pnp.cjs`.

Редакция N1RO · Проверено

Короткий ответ

Если после `yarn install` нет `node_modules`, проверьте `.yarnrc.yml`: при `nodeLinker: pnp` это ожидаемо. Для совместимых проектов оставьте PnP и настройте IDE; если инструмент требует физический `node_modules`, задайте `nodeLinker: node-modules` и снова выполните `yarn install`.

Как Yarn PnP работает без node_modules

В режиме Plug'n'Play Yarn не строит традиционное дерево `node_modules`. Вместо этого он создаёт загрузчик `.pnp.cjs`, содержащий сведения о зависимостях и их расположении. Когда приложение импортирует пакет, Yarn определяет, какая зависимость разрешена конкретному пакету и где лежат её файлы. Это уменьшает файловые операции при установке и помогает обнаруживать ghost dependencies — ситуации, когда код использует пакет, не объявленный в собственных зависимостях. Поэтому ошибка PnP не всегда означает несовместимость Yarn: иногда она выявляет реальный дефект `package.json`. Сначала прочитайте сообщение и проверьте manifest, а не переключайтесь на node_modules автоматически.

Что делать, если проект не запускается в PnP

  1. 1: Откройте `.yarnrc.yml` и проверьте `nodeLinker`. При `pnp` отсутствие `node_modules` нормально.
  2. 2: Запускайте project scripts через Yarn, чтобы процесс получил правильный resolver.
  3. 3: Если ошибка говорит о неописанной зависимости, добавьте её в тот workspace/package.json, который реально её импортирует.
  4. 4: Если терминал работает, а IDE нет, настройте проектный SDK и PnP-интеграцию редактора.
  5. 5: Если критичный инструмент принципиально требует `node_modules`, задайте `nodeLinker: node-modules` и выполните новый `yarn install`.

Совет: Переключение linker — штатная возможность Yarn. Не нужно вручную создавать `node_modules` рядом с PnP-проектом.

Три install mode в Yarn

  • pnp. `.pnp.cjs`, без обычного node_modules. Современный проект, инструменты поддерживают PnP
  • node-modules. Традиционный `node_modules`. Инструмент требует файловую структуру node_modules
  • pnpm linker Yarn. node_modules со store/links по pnpm-подобной схеме. Нужна совместимость node_modules с более строгой схемой ссылок

Почему IDE показывает красные импорты, а yarn test проходит

Запущенный через Yarn процесс получает PnP-окружение и умеет разрешать зависимости через loader. IDE может использовать собственный TypeScript, ESLint или language server, запущенный вне этого контекста. Тогда редактор ищет привычный `node_modules` и считает импорт отсутствующим. Решение — настроить рекомендованный Yarn SDK или интеграцию для конкретного редактора, а не добавлять фиктивные зависимости. После настройки перезапустите language server и проверьте, что редактор использует версию инструмента из проекта. Если команда в терминале тоже падает, проблема уже не только в IDE: тогда проверяйте декларации зависимостей и возможные `packageExtensions` для стороннего пакета с неправильным manifest.

Когда лучше перейти на node-modules

Yarn поддерживает обычный node-modules linker как полноценный режим. Он уместен, если критичный инструмент самостоятельно обходит файловую структуру и не умеет работать через PnP resolver, а обновить его нельзя. Документация Yarn отдельно отмечает React Native/Expo как заметный сценарий, где типичный `node_modules` остаётся практичнее. После переключения обязательно закоммитьте `.yarnrc.yml` и убедитесь, что CI использует ту же конфигурацию. Не держите локально PnP, а на сборке node-modules без явной причины: разные layout усложняют воспроизведение ошибок и могут скрывать ghost dependencies, которые PnP обнаруживал раньше.

Проверка миграции между PnP и node_modules

  • `.yarnrc.yml` закоммичен и одинаков у команды и CI.
  • После смены `nodeLinker` выполнен новый `yarn install`.
  • Скрипты не обращаются напрямую к `node_modules/.bin`, если проект остаётся на PnP.
  • Зависимости объявлены в том workspace, который реально их импортирует.
  • IDE использует проектный SDK или корректную PnP-интеграцию.
  • Старые артефакты предыдущего режима не участвуют в сборке.

Предупреждение: Не добавляйте отсутствующий пакет в корень workspace только для того, чтобы исчезла PnP-ошибка: это может скрыть неверный manifest конкретного пакета.

Что дают ошибки ghost dependency и packageExtensions

В традиционном hoisted `node_modules` пакет иногда может импортировать библиотеку, которую сам не объявил, просто потому что она случайно оказалась выше в дереве. PnP блокирует такой доступ и объясняет, кто пытался получить пакет и почему это не разрешено. Если проблема в вашем коде, исправление — объявить зависимость там, где она используется. Если ошибается сторонний пакет и быстро обновить его нельзя, Yarn поддерживает `packageExtensions`, позволяющий дополнить его declaration на уровне конфигурации проекта. Это лучше, чем хаотично менять layout ради одного дефектного пакета. Но если несовместимый инструмент принципиально читает `node_modules`, чище использовать официальный node-modules linker.

Как отличить несовместимость инструмента от неверной зависимости

Если ошибка PnP сообщает, что конкретный пакет пытается получить зависимость, которой нет в его manifest, это не то же самое, что инструмент, ищущий физический каталог `node_modules`. В первом случае правильный путь — исправить декларацию зависимости, обновить пакет или временно использовать `packageExtensions`. Во втором случае программа может напрямую обходить файловую систему и просто не понимать PnP layout. Тогда имеет смысл проверить актуальную версию инструмента и его документацию, а при отсутствии поддержки переключить проект на `nodeLinker: node-modules`. Разделение этих двух ситуаций важно: иначе команда может отказаться от PnP из-за одной обычной ghost dependency, которую можно исправить без смены всей стратегии установки.

Как перевести существующий проект на PnP без хаотичных исправлений

Миграцию лучше начинать в отдельной ветке с чистым рабочим деревом. Включите `nodeLinker: pnp`, выполните `yarn install` и затем запускайте обычные test, build и lint-команды проекта. Ошибки разбирайте по типу: если Yarn сообщает о ghost dependency, исправляйте manifest того workspace, который импортирует пакет; если ломается IDE, настройте SDK; если сторонняя библиотека имеет неполные метаданные, рассмотрите `packageExtensions`. Только когда проблема действительно связана с инструментом, который требует физический `node_modules`, имеет смысл возвращаться к `nodeLinker: node-modules`. Такой порядок сохраняет диагностическую ценность PnP. Если переключиться обратно после первой же ошибки, можно замаскировать зависимость, которая и раньше была объявлена неправильно, но случайно находилась благодаря hoisting.

Как держать одинаковый install mode у разработчиков и в CI

Файл `.yarnrc.yml` должен быть частью репозитория, а не локальной настройкой одного разработчика. Тогда `nodeLinker` одинаково применяется на рабочей машине и в CI-процесс. После изменения режима выполните чистую установку и убедитесь, что в сборке не осталось предположений о старом layout, например прямых путей к `node_modules/.bin`. Если команда поддерживает несколько редакторов, документируйте только необходимые шаги интеграции PnP, а не заставляйте каждого вручную искать обходной путь. Для проблемного инструмента проверьте актуальную поддержку PnP до глобальной смены стратегии установки. Если всё же выбираете `node-modules`, это не считается «неправильным Yarn»: официальная документация называет этот linker полноценным поддерживаемым режимом. Главное — чтобы решение было единым для проекта и воспроизводилось в CI.

Почему отсутствие node_modules само по себе не ошибка

В PnP-проекте критерий исправности — успешное разрешение зависимостей и прохождение команд проекта, а не наличие привычной папки. Если `yarn test` и сборка работают, создавать `node_modules` вручную только ради визуального привычного состояния не нужно.

Что учитывать

Запущенный через Yarn процесс получает PnP-окружение и умеет разрешать зависимости через loader. IDE может использовать собственный TypeScript, ESLint или language server, запущенный вне этого контекста. Тогда редактор ищет привычный `node_modules` и считает импорт отсутствующим. Решение — настроить рекомендованный Yarn SDK или интеграцию для конкретного редактора, а не добавлять фиктивные зависимости. После настройки перезапустите language server и проверьте, что редактор использует версию…

Источники и проверка

Фактическая часть сверена по первичным источникам (в т.ч. Plug'n'Play). Пример и формулировки — редакция N1RO на 2026-09-20.