2026: матрица Sharp, libvips и ImageMagick — потоки, пики памяти и кэш CI при статической сборке
Для кого: команды фронтенда и 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 при общем термобюджете.
- Неконтролируемый параллелизм в циклах даёт N одновременных декодов — ограничьте очередью (
p-limit, Bottleneck или размер пулаworker_threads). - Временные файлы на медленном томе маскируются как «упор в CPU»; задайте
TMPDIRна локальный SSD, например.cache/img-tmpв репозитории на диске узла. - Промахи кэша в 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. |
Зафиксируйте кучу и потоки в одном месте. Фрагмент 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.
- Куча V8 по умолчанию часто остаётся в диапазоне около 2–4 ГБ, пока не задан
--max-old-space-size. - VIPS_CONCURRENCY около половины P‑ядер — типичный стабильный старт на классе M4.
- MAGICK_THREAD_LIMIT=1 полезен для отладки делегатов и взаимных блокировок перед повышением потоков.
03 Удалённый Mac: приёмка в три шага
Используйте в staging CI ту же конфигурацию Apple Silicon, что и у арендованного продакшен-узла: приёмка показывает, что пайплайн укладывается в swap и SLO по времени.
- Профиль на тысяче файлов. Зафиксируйте wall time, пик RSS через Activity Monitor или
ps, объём записи во временный каталог. Сравните Sharp и CLI, если стек ещё выбираете. - Заморозьте версии. Закрепите semver Sharp, системные
vipsиmagickв ключе кэша и в README для CI. - Повтор с боевым окружением. Уберите отладочный шум; включите те же
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 mini M4 под SSG и пакетную обработку изображений
Локальный SSD, стабильные SSH-сессии и предсказуемая RAM для Sharp и libvips. Откройте публичную страницу тарифов без входа, выберите конфигурацию и зафиксируйте VIPS_CONCURRENCY под реальное железо арендованного узла.