Пакетный менеджер pnpm завоевал признание благодаря архитектуре контентно-адресуемого хранилища (Content-Addressable Store, CAS). Вместо копирования сотен мегабайт идентичных файлов pnpm сохраняет пакеты на диске в единственном экземпляре, собирая дерево зависимостей node_modules через жесткие ссылки и симлинки. Однако на масштабе крупных монорепозиториев эта схема упирается в ограничения файловых систем.
При десятках тысяч зависимостей генерация разветвленного леса симлинков создает ощутимую нагрузку на метаданные диска. В контейнерах Docker, на сетевых хранилищах NFS и в Windows NTFS этап связывания файлов может отнимать до трети времени развертывания проекта в CI.
Синхронный выпуск pnpm 12.10.0 и патч-релиза ветки 11.28.5 решает эту проблему ввода-вывода и закрывает несколько векторов уязвимостей.
Режим loaded: разрешение зависимостей без симлинков
Ключевое новшество релиза — экспериментальный компоновщик nodeLinker: { type: loaded }. В этом режиме pnpm полностью отказывается от создания физических симлинков в папке node_modules.
Вместо манипуляций с файловой структурой менеджер генерирует манифест .store-manifest.json и файл хуков загрузчика .store-loader.mjs. Разрешение модулей переносится в память процесса Node.js: рантайм считывает зарегистрированный лоадер и подгружает пакеты напрямую из глобального хранилища CAS.
Для модулей со скомпилированными бинарниками C++ или нестандартным чтением путей через __dirname предусмотрена директива excluded, возвращающая выбранные пакеты к классическому связыванию:
# .npmrc / pnpm-workspace.yaml — активация loaded-линкера и параметров надежности
node-linker:
type: loaded
# Изоляция нативных пакетов для совместимости с FFI
excluded:
- '@swc/core'
- 'better-sqlite3'
# Сохранение правил дедупликации в манифесте блокировок для стабильности CI
lockfile:
include-resolution-settings: true
Воспроизводимость сборок на серверах интеграции
Второй фокус обновления — опция lockfile.includeResolutionSettings: true. Ранее параметры дедупликации зависимостей (autoDedupe, dedupePeerDependents) считывались только из пользовательского файла .npmrc.
Если разработчик настраивал локальную дедупликацию, генерировал lockfile и отправлял коммит, пайплайн CI в облаке мог упасть: команда pnpm install --frozen-lockfile на чистом сервере видела расхождение в графе из-за отсутствия локальных флагов. Включение опции сохраняет точные правила разрешения конфликтов версий непосредственно внутри pnpm-lock.yaml, гарантируя идентичный результат на любой машине.
Установка и запуск проектов с новым линкером выполняются привычным набором команд:
# Проверка и установка зависимостей в проекте с новым линкером
# 1. Быстрая установка зависимостей без создания физических симлинков
pnpm install
# 2. Запуск приложения с подключением сгенерированного загрузчика Node.js
node --import ./node_modules/.store-loader.mjs index.mjs
# 3. Верификация графа зависимостей на сервере непрерывной интеграции
pnpm install --frozen-lockfile
Защита от вредоносных архивов и обхода путей
Релизы также закрывают важные угрозы безопасности:
- Блокировка Path Traversal: устранена уязвимость, при которой пакет мог содержать относительные симлинки, позволяющие выйти за пределы хранилища pnpm и получить доступ к файлам хоста.
- Лимит распаковки 64 МиБ: жесткое ограничение на объем метаданных распаковываемых архивов блокирует атаки класса «декомпрессионная бомба» (zip bomb), вызывавшие переполнение памяти.
- Изоляция метаданных v12: сетевой кэш ответов реестра перенесен в изолированный каталог
<cache-dir>/v12/для исключения коллизий версий.
Практические выводы
Режим loaded node linker демонстрирует новый вектор развития экосистемы Node.js: перенос логики разрешения модулей из файловой системы в виртуальные рантайм-хуки. В отличие от жесткого подхода Yarn PnP, pnpm сохраняет возможность точечного исключения нативных библиотек через excluded, обеспечивая гладкую миграцию.
Командам крупных монорепозиториев имеет смысл протестировать режим loaded и активировать lockfile.includeResolutionSettings: true для устранения нестабильных падений сборок на серверах CI.
