Трансграничная задержка: сравнение времени двух режимов (PnP и node_modules)
На хостинге удалённого Mac CI холодный yarn install упирается в TLS, RTT и объём tarball’ов, а не в локальный CPU. Yarn Berry с PnP (nodeLinker: pnp) снижает лавину мелких записей: один .pnp.cjs и сжатый .yarn/cache — часто выигрыш, когда зеркало registry далеко, а APFS быстрый. Классический node_modules (nodeLinker: node-modules) раздувает inode; он уместен, если инструменты ждут физические пути или postinstall уже переписывает дерево.
| Режим | Типичный выигрыш на удалённом Mac | Трансграничный угол | Ограничение гибридного monorepo |
|---|---|---|---|
| PnP | Меньше метаданных после прогрева кеша; меньше файлов на фазе линковки | Число tarball’ов как у node_modules; выигрыш после попадания пакетов в .yarn/cache |
Metro, Jest или iOS-скрипты могут потребовать sdk или linker node-modules точечно |
| node_modules | Максимальная совместимость со «статом» глубоких деревьев | Высокий RTT больнее при множестве мелких пакетов — жёстко настраивайте параллельную установку | Предсказуемо для скриптов рядом с CocoaPods, ожидающих hoisted-пути |
| PnP + loose (компромисс) | Смягчает строгую резолюцию для части пакетов | Сетевой профиль близок к строгому PnP | Зафиксируйте причину «loose» — security-ревью спросит |
Ни один режим не отменяет близкое зеркало registry и HTTP/2-дружелюбный egress. Сравнивайте «PnP в 2 раза быстрее» только вместе с географией, числом хопов до зеркала и холодным/тёплым кешом.
Зеркало npm / Yarn: параметры .yarnrc.yml и сеть
Один источник правды для endpoint’ов registry. Для удалённого Mac CI согласуйте с security hostname зеркала и явные таймауты, чтобы job падал с ошибкой, а не «висел». Чеклист связывает Yarn 4 с операционным смыслом.
npmRegistryServer— зеркало или апстрим по политике.networkConcurrency— потолок параллельной установки для трансграничных раннеров (старт 12–20, затем метрики).httpTimeout— худший случай tarball (часто 60–120 с на «шумных» линках).httpRetry— ограниченные повторы для 5xx/429 по внутренним правилам SRE.enableGlobalCache: trueтолько на выделенных тёплых хостах с изоляцией тенантов.checksumBehaviorв CI —throw, кроме аудируемых исключений.
# Фрагменты .yarnrc.yml — подставьте хосты; секреты не коммитить nodeLinker: pnp # или node-modules compressionLevel: mixed npmRegistryServer: "https://registry.npmmirror.com" # пример зеркала # Ограничить параллельные загрузки при высокой задержке networkConcurrency: 16 httpTimeout: 90000 httpRetry: 3 # CI: упасть, если lockfile изменится enableImmutableInstalls: true # Опционально: глобальный кеш только на выделенных Mac mini # enableGlobalCache: true # Внутреннее зеркало без TLS — только с allowlist # unsafeHttpWhitelist: # - "npm.internal.corp"
Сочетайте с Node 22+ и corepack enable, чтобы ноутбуки и агенты Apple Silicon брали одну линию yarnPath.
GitHub Packages и npm: двойная аутентификация и ротация токенов
Гибридные команды тянут публичное с npmjs, а приватные @org/* держат в GitHub Packages. В Yarn — npmScopes; токены только из переменных CI, не литералами в git. При ротации держите два перекрывающихся секрета минимум один цикл пайплайна: NPM_TOKEN и GITHUB_PACKAGES_TOKEN из vault.
# .yarnrc.yml — переменные окружения; значения в секретах CI
npmScopes:
myorg:
npmRegistryServer: "https://npm.pkg.github.com"
npmAlwaysAuth: true
npmAuthToken: "${GITHUB_PACKAGES_TOKEN}"
npmRegistries:
"https://registry.npmjs.org":
npmAuthToken: "${NPM_READ_TOKEN}"
Минимум прав: для install — read:packages на GitHub; публикация — отдельные workflow с узкими scope. Если зеркало registry в другой юрисдикции, согласуйте TLS-инспекцию и логирование с compliance — это не только latency.
Параллелизм CI, параллельная установка и пороги диска (watermark)
Параллельные job’ы умножают одновременные fetch tarball’ов. Ограничивайте и networkConcurrency, и лимиты оркестратора на узел. На диске node_modules в крупных monorepo легко десятки гигабайт; PnP смещает байты в .yarn/cache, но распаковка всё равно нужна. В runbook задайте три уровня: предупреждение (например свободно < 30 ГБ), троттлинг (не брать новые job), стоп (fail до порчи установки).
На общих пулах удалённого Mac коррелируйте алерты диска с фазой yarn install и Xcode DerivedData. Про кеш компиляции — матрица sccache и ccache; про смежные экосистемы — conda / mamba на удалённом Mac CI.
Повторы при сбоях, backoff и приёмка согласованности lockfile
Оборачивайте yarn install --immutable в ограниченный backoff (например 2, 4, 8 с) на транспортных ошибках, но не повторяйте вслепую нарушения checksum — это скрывает дрейф цепочки поставок. Ворота merge: одинаковый отпечаток yarn.lock на чистых macOS-агентах, отсутствие ошибок класса YN0028 на чистом checkout, зафиксированная версия Yarn в метаданных сборки.
#!/usr/bin/env bash
set -euo pipefail
corepack enable
corepack prepare yarn@stable --activate
attempt=1 max=4 delay=2
while [ "$attempt" -le "$max" ]; do
echo "yarn install попытка $attempt/$max"
if yarn install --immutable 2>&1 | tee "yarn-install-${attempt}.log"; then
exit 0
fi
# Не повторять immutable / checksum (например YN0028)
if grep -qE 'YN0028|checksumBehavior|checksum' "yarn-install-${attempt}.log"; then
exit 1
fi
sleep "$delay"
delay=$((delay * 2))
attempt=$((attempt + 1))
done
exit 1
Флаки, которые проходят после перезапуска без кода, часто — лимиты зеркала registry, а не тесты; чините уровень registry раньше, чем jest.retryTimes на чужих шагах.
FAQ
По умолчанию PnP в новых monorepo в 2026? Да, если веб-стек поддерживает из коробки и нужно снять давление на inode на общих Mac; node-modules — если доминирует мобильный/нативный мост и нет бюджета на резолверы.
Ослабляет ли зеркало supply-chain? Только если отключать проверки целостности. Держите checksumBehavior: throw, зеркала только из allowlist, TLS зеркала — как у любого прокси зависимостей.
Связь с CocoaPods / SwiftPM? Стратегия JS независима, но конкурирует за диск и сеть на том же хосте — планируйте тяжёлый yarn install относительно prefetch нативных артефактов.
Смешивать linker’ы в одном репо? Yarn допускает dependenciesMeta точечно; документируйте — смешанный режим усложняет поддержку.
Итог
Yarn Berry и PnP выбирайте, когда inode и размер дерева дороже настройки резолвера; классический node_modules — когда совместимость дешевле, чем борьба с Metro и нативными скриптами. В обоих случаях удалённый Mac CI держится на управляемом зеркале registry, раздельных токенах npm и GitHub Packages, умеренной параллельной установке, порогах диска, неизменяемом lockfile и честных повторах без маскировки checksum.
Нужна предсказуемая очередь на Apple Silicon под Node 22+ и вашу схему зеркал — откройте страницу цен, покупку и аренду узла и центр помощи на macpull.com (читать можно без входа), начните с небольшого пула раннеров перед миграцией всего monorepo. Актуальные плейбуки — в каталоге блога рядом с материалами по registry и кешу.