SSG · Изображения · Remote Mac · 2026

2026: матрица Sharp, libvips и ImageMagick — потоки, пики памяти и кэш CI при статической сборке

07.04.2026 Фронтенд / Full-stack 9 мин чтения

Для кого: команды фронтенда и fullstack, которые на удалённом Mac гоняют SSG или пререндер и генерируют сотни миниатюр и responsive-наборов без OOM и без заторов диска. Ниже — решение в одной матрице для Sharp (Node поверх libvips), libvips (CLI или прямой вызов) и ImageMagick 7: форматы, переменные параллелизма, временные каталоги, риск нехватки памяти, стратегия кэша в CI и готовые фрагменты package.json с NODE_OPTIONS. См. также: память Node и PostCSS/Tailwind, кэш Vite и webpack, preflight скриптов в package.json.

01 Сценарий SSG: массовые миниатюры и производные размеры

Документация и витрины часто делают 3–8 производных на файл в npm run build. На арендованном Mac типичный сбой — не CPU, а перекрывающиеся декоды, медленный TMPDIR и лишние потоки на P‑ядрах Apple Silicon.

Один стек на репозиторий: не смешивайте пул Sharp с magick в одной job. Параллелизм: ядер минус один локально или половина потоков на shared runner при общем термобюджете.

  1. Неконтролируемый параллелизм в циклах даёт N одновременных декодов — ограничьте очередью (p-limit, Bottleneck или размер пула worker_threads).
  2. Временные файлы на медленном томе маскируются как «упор в CPU»; задайте TMPDIR на локальный SSD, например .cache/img-tmp в репозитории на диске узла.
  3. Промахи кэша в CI вынуждают холодно пересобирать WebP/AVIF; ключируйте артефакты по checksum исходника и версии тулчейна, а не только по имени ветки.

02 Три решения: таблица параметров (Sharp, libvips, ImageMagick)

Рычаги для .env.ci или prelude перед pnpm run build. Sharp наследует libvips; при CLI vips рядом VIPS_CONCURRENCY — общий кап пика.

Измерение Sharp (Node + libvips) libvips (CLI / API) ImageMagick 7
Применимые форматы JPEG, PNG, WebP, AVIF, TIFF, SVG→растр; лучше, если всё в Node. Как в вашей сборке libvips; пакетный resize, пирамиды для TIFF. Делегаты, PSD/RAW, экзотика; выше overhead.
Переменные параллелизма VIPS_CONCURRENCY; опционально UV_THREADPOOL_SIZE для ФС; отдельно кап очереди Sharp в JS. VIPS_CONCURRENCY; держите не выше числа P‑ядер для стабильного RSS. MAGICK_THREAD_LIMIT; при OpenMP — OMP_NUM_THREADS, если потоков слишком много.
Временный каталог Системный temp; задайте TMPDIR на локальный SSD, не NFS home. Тяжёлый random I/O; тот же TMPDIR, смотрите df. MAGICK_TEMPORARY_PATH + TMPDIR; делегаты — проверка verbose один раз.
Риск OOM Пики при ширине декода × каналы; смотрите RSS node и нативную сторону — сначала снижайте параллелизм, потом поднимайте кучу. Большие буферы строк сканирования; уменьшайте потоки до расширения лимитов пикселей. Цепочки фильтров дублируют растры; в CI задавайте -limit memory и -limit map.
Кэш в CI node_modules + .cache/images по checksum; ключ с версией libvips в Sharp. Кэш миниатюр; ключ vips --vips-version. Делегаты — осторожно; ключ magick -version + hash policy.xml.
Исполняемые скрипты npm / pnpm и NODE_OPTIONS

Зафиксируйте кучу и потоки в одном месте. Фрагмент package.json:

{
  "scripts": {
    "img:ssg": "NODE_OPTIONS='--max-old-space-size=6144' node ./scripts/generate-thumbnails.mjs",
    "img:ssg:safe": "VIPS_CONCURRENCY=4 MAGICK_THREAD_LIMIT=4 TMPDIR=$PWD/.cache/img-tmp pnpm run img:ssg"
  }
}

SSH, 16 ГБ: export NODE_OPTIONS=--max-old-space-size=6144, export VIPS_CONCURRENCY=4, mkdir -p .cache/img-tmp.

Три цифры для runbook
  • Куча V8 по умолчанию часто остаётся в диапазоне около 2–4 ГБ, пока не задан --max-old-space-size.
  • VIPS_CONCURRENCY около половины P‑ядер — типичный стабильный старт на классе M4.
  • MAGICK_THREAD_LIMIT=1 полезен для отладки делегатов и взаимных блокировок перед повышением потоков.

03 Удалённый Mac: приёмка в три шага

Используйте в staging CI ту же конфигурацию Apple Silicon, что и у арендованного продакшен-узла: приёмка показывает, что пайплайн укладывается в swap и SLO по времени.

  1. Профиль на тысяче файлов. Зафиксируйте wall time, пик RSS через Activity Monitor или ps, объём записи во временный каталог. Сравните Sharp и CLI, если стек ещё выбираете.
  2. Заморозьте версии. Закрепите semver Sharp, системные vips и magick в ключе кэша и в README для CI.
  3. Повтор с боевым окружением. Уберите отладочный шум; включите те же NODE_OPTIONS, TMPDIR и лимиты потоков, что в таблице выше.

Пять проверок: ≥20% на SSD; нет rm -rf dist в watch; одна версия Sharp в monorepo; AVIF совпадает с деплоем; этап картинок не параллелит пик CSS/бандлера.

04 FAQ

Дублирует ли Sharp настройки libvips на удалённом Mac?

Да: resize/encode через libvips. VIPS_CONCURRENCY + куча Node и libuv настраиваются вместе, не по отдельности на максимум.

Когда выбирать ImageMagick вместо libvips для SSG?

Делегаты и редкие форматы. Для JPEG/WebP/AVIF при капе потоков libvips или Sharp обычно быстрее и стабильнее по RSS.

Какой NODE_OPTIONS разумен для 16 ГБ на runner?

6144 МБ old space и ≤4 тяжёлых декода; при swap сначала режьте потоки, не кучу.

Вывод

Sharp, libvips и ImageMagick на Apple Silicon работают предсказуемо, если зафиксированы потолки потоков, быстрый temp и checksum-ключи кэша. Прогоняйте приёмочный срез на том же удалённом Mac build-узле, что и в CI. Публичные страницы без обязательного входа: тарифы, аренда и покупка, помощь и SSH — чтобы подобрать ноду под длительные пакетные задачи с изображениями.

Узлы сборки на удалённом Mac

Выделенный Mac mini M4 под SSG и пакетную обработку изображений

Локальный SSD, стабильные SSH-сессии и предсказуемая RAM для Sharp и libvips. Откройте публичную страницу тарифов без входа, выберите конфигурацию и зафиксируйте VIPS_CONCURRENCY под реальное железо арендованного узла.

Миниатюры и AVIF Под CI и билды SSH и автоматизация
Узлы для сборки