Pipeline images · SSG · Mac distant · 2026

2026 Matrice front-end / full-stack :
Sharp, libvips et ImageMagick — concurrence, mémoire et cache pour sites statiques

07.04.2026 Front-end & plateforme 10 min de lecture

Builds SSG avec milliers de miniatures sur Mac distant : le goulot est souvent le pic RSS, un TMPDIR lent et une concurrence mal réglée entre le pool libuv et libvips. Matrice Sharp (Node + libvips), libvips en CLI et ImageMagick : formats, variables et API de parallélisme, temporaires, OOM, cache CI, scripts npm/pnpm. Croiser avec mémoire Next/Nuxt et caches Vite/Webpack.

01 Scénario SSG : génération massive de miniatures

Chaque source peut produire plusieurs variantes (WebP, AVIF, JPEG, largeurs multiples). Sur macOS distant, la marge RAM utile se réduit avec sshd, autres jobs et parfois une session graphique.

Trois tensions : (1) concurrence trop haute → RAM avant CPU ; (2) TMPDIR réseau → latence et mesures faussées ; (3) cache CI sans version binaire Sharp/libvips/ImageMagick → sorties divergentes.

PostCSS/Tailwind chargent aussi le tas Node : voir la matrice Tailwind v4 / PostCSS avant d’attribuer tous les OOM aux images.

02 Matrice décisionnelle : Sharp, libvips et ImageMagick

Leviers opérationnels 2026 ; concurrence indicative — calibrez sur votre corpus.

Critère Sharp (Node + libvips) libvips (CLI / bindings directs) ImageMagick
Formats & cas d’usage JPEG, PNG, WebP, AVIF, TIFF, GIF ; scripts npm, SSG (Astro, Gatsby, export Next). vips en shell ou bindings hors Node. Large couverture ; legacy, magick/convert.
Concurrence (env / API) sharp.concurrency(n) dans le script ; UV_THREADPOOL_SIZE (avant le démarrage Node) pour le parallélisme entre images ; option VIPS_CONCURRENCY pour libvips. Plafonner les lots applicatifs. VIPS_CONCURRENCY=<n> ; VIPS_DISC_THRESHOLD (ex. 50m200m) pour lisser la RAM. MAGICK_THREAD_LIMIT 1–4 ; OMP_NUM_THREADS aligné si OpenMP.
Répertoire temporaire TMPDIR → dossier APFS local (ex. .tmp-sharp). TMPDIR=$PWD/.tmp-vips ; pas de NFS scratch. TMPDIR explicite ; surveiller l’espace disque.
Risque OOM / pic mémoire Tas Node (NODE_OPTIONS) + natif libvips ; baisser sharp.concurrency et UV_THREADPOOL_SIZE avant de monter seul le heap JS. Souvent bon débit/RAM en batch ; seuil disque limite les pics sur très gros fichiers. Pics souvent plus hauts ; sérialiser ou threads bas sur 16–24 Go partagés.
Cache CI Sorties + lockfile ; clé avec version sharp/ABI. Image outil + sorties ; vips --version dans la clé. magick -version + policy.xml ; caches outil vs sorties séparés.

03 Scripts npm / pnpm et NODE_OPTIONS (exemples exécutables)

Avec cross-env ; pnpm run <script> sous pnpm.

package.json — extraits
{
  "scripts": {
    "ssg:img:sharp": "cross-env NODE_OPTIONS='--max-old-space-size=8192' UV_THREADPOOL_SIZE=8 VIPS_CONCURRENCY=4 TMPDIR=$PWD/.tmp-images node ./tools/generate-responsive.mjs",
    "ssg:img:vips": "cross-env VIPS_CONCURRENCY=4 VIPS_DISC_THRESHOLD=100m TMPDIR=$PWD/.tmp-images bash ./tools/vips-batch.sh",
    "ssg:img:magick": "cross-env MAGICK_THREAD_LIMIT=2 OMP_NUM_THREADS=2 TMPDIR=$PWD/.tmp-images bash ./tools/magick-batch.sh"
  }
}

Cinq étapes : .gitignore pour .tmp-images ; mêmes env en CI ; clé de cache avec versions outils ; dry-run ~10 fichiers pour RSS ; README plateforme avec plafonds.

Dans generate-responsive.mjs, appelez tôt sharp.concurrency(4) (ou la valeur mesurée) pour borner les fils libvips par image ; UV_THREADPOOL_SIZE doit être défini avant le lancement du processus Node, pas dans un hook tardif.

04 Acceptation sur Mac distant en trois étapes

1 — Mémoire : build complet sur le commit ; RSS max et swap. Si swap > ~2 Go >1 min, réduire UV_THREADPOOL_SIZE, sharp.concurrency ou VIPS_CONCURRENCY par paliers.

2 — Sorties : hashes (SHA-256 ou perceptuel) sur échantillon avant/après cache CI ; divergence = clé d’artefact ou binaire mal versionné.

3 — Hôte partagé : SSH utilisable pendant le job ; sinon créneaux CI ou concurrence réduite.

05 FAQ

Sharp et libvips doublonnent-ils ?

Sharp utilise libvips en natif ; « libvips seul » = CLI ou bindings hors Node. VIPS_CONCURRENCY et sharp.concurrency() ciblent libvips ; UV_THREADPOOL_SIZE borne le parallélisme entre images côté libuv.

Quand ImageMagick ?

Legacy, formats rares, recettes existantes ; job isolé, threads bas, TMPDIR local.

NODE_OPTIONS suffit pour Sharp ?

Non : seulement le tas JS ; le natif libvips peut OOM — baisser la concurrence et normaliser les sources.

Synthèse

Les nouveaux pipelines SSG privilégient Sharp ou libvips direct ; réservez ImageMagick au legacy isolé. La livrable sur Mac loué est une courbe RSS plate, des sorties reproductibles après cache CI, et une session SSH encore confortable pendant le build.

Trois repères réutilisables

Point de départ sur Mac 16–24 Go partagé : VIPS_CONCURRENCY=4, UV_THREADPOOL_SIZE=8 avec sharp.concurrency(4) dans le code, MAGICK_THREAD_LIMIT=2.

Toujours fixer TMPDIR vers un dossier local APFS sous le workspace avant les lots SSG.

Inclure dans la clé de cache CI les versions sharp, vips et la sortie de magick -version, plus le hash du dossier sources d’images.

Nœud de build : accueil, tarifs, aide, blog. Louer une capacité pour NVMe local et mesures de concurrence fiables.

Nœud de build Mac distant

SSG et miniatures sur Mac loué

APFS pour TMPDIR, cœurs réels pour calibrer UV_THREADPOOL_SIZE et VIPS_CONCURRENCY, marge pour Node + natif. Pages publiques MacWww puis branchez votre runner CI.

Pipelines images Mac distant Apple Silicon
Louer un Mac — sans connexion