Depuis que je me suis intéressé sérieusement aux Core Web Vitals, j'ai appris que les images représentent souvent le plus gros levier d'optimisation pour améliorer le LCP, la vitesse perçue et la consommation de données. Pour mes projets sur Flyweb et pour des clients, j'aime automatiser la génération d'images responsives afin d'offrir des images à la bonne taille et au bon format — sans multiplier les tâches manuelles. Dans cet article, je vous partage ma méthode pratique pour automatiser cette génération avec sharp et Vercel, tout en expliquant comment cela aide concrètement vos Core Web Vitals.

Pourquoi automatiser les images ?

Je vois trop souvent des sites qui chargent des images gigantesques sur mobile, ou qui servent du PNG quand WebP ou AVIF seraient bien plus appropriés. Automatiser permet de :

  • servir la bonne résolution selon l'appareil et la densité d'écran,
  • convertir automatiquement en formats modernes (WebP, AVIF),
  • mettre en place des en-têtes de cache et une invalidation simple,
  • réduire le poids total de la page, donc améliorer le LCP et réduire la consommation data.
  • Avec sharp, on peut traiter, redimensionner et convertir des images rapidement. Sur Vercel, les serverless functions (ou les Edge Functions selon besoin) permettent de déployer ce pipeline de manière scalable et proche de l'utilisateur.

    Architecture simple que j'utilise

    Voici l'architecture que j'ai mise en place pour la plupart de mes sites :

  • Stockage original : CDN ou bucket (S3, DigitalOcean Spaces, ou un stockage interne),
  • Endpoint d'optimisation : fonction serverless sur Vercel qui récupère l'image originale, la transforme avec sharp et renvoie l'image optimisée,
  • Cache CDN : Vercel met en cache les réponses, et on ajoute des headers Cache-Control pour prolonger la durée côté client et CDN,
  • HTML responsive : balises picture/srcset/sizes ou attribut srcset sur img générés dynamiquement par le backend ou au build time.
  • Flux de traitement étape par étape

    Dans la fonction qui s'exécute chez Vercel :

  • je récupère l'URL de l'image d'origine et les paramètres (largeur souhaitée, format, qualité),
  • je valide et limite les paramètres pour éviter l'abus (par ex. max-width = 3840),
  • je télécharge l'image originale depuis le stockage si elle n'est pas déjà en cache,
  • j'applique les transformations avec sharp : redimensionnement, crop ou fit, conversion en WebP/AVIF si demandé, optimisation de la qualité, suppression des métadonnées si inutile,
  • je renvoie l'image avec les bons en-têtes : Content-Type, Cache-Control (public, max-age, stale-while-revalidate), ETag/Last-Modified pour validation côté CDN/clients.
  • Ce pipeline est très flexible : on peut ajouter un watermark, des transformations intelligentes (adaptation à la couleur dominante), ou un heuristique pour choisir entre WebP/AVIF selon l'accept header du client.

    Comment cela aide les Core Web Vitals

    Voici les bénéfices concrets que j'ai observés après avoir déployé ce système :

  • LCP plus rapide : servir une image dimensionnée réduit le temps de téléchargement initial et la taille à décoder,
  • CLS réduit : en générant des images qui respectent les attributs width/height ou en utilisant un CSS aspect-ratio calculé, on évite les sauts de mise en page,
  • FCP amélioré : des images plus petites arrivent plus vite, ce qui accélère l'affichage visuel de la page,
  • Réduction du TTFB en production grâce au cache CDN et au pré-calcul lorsque nécessaire.
  • Bonnes pratiques HTML/CSS à combiner

  • utiliser l'élément picture avec des sources pour proposer AVIF/WebP/format fallback,
  • inclure des attributs width et height dans les img ou utiliser aspect-ratio pour éviter les CLS,
  • déclarer srcset et sizes pour permettre au navigateur de choisir la meilleure variante,
  • précharger l'image la plus critique (link rel="preload" as="image") si elle est determinante pour le LCP,
  • lazy-loading pour les images non critiques (loading="lazy"),
  • définir des placeholders légers (SVG blur, tiny LQIP) pour une expérience perçue plus fluide.
  • Choix de formats : tableau rapide

    FormatAvantagesInconvénients
    AVIFMeilleure compression, haute qualité à faible taillesupport pas universel sur anciens navigateurs, encodage plus lourd
    WebPLarge support, bon ratio qualité/poidsencodage encore plus lent qu'un JPEG simple pour certains workflows
    JPEGcompatibilité totalepoids généralement plus élevé, pas de transparence
    PNGtransparence, qualité sans pertetaille souvent supérieure, pas idéal pour photos

    Cache, CDN et invalidation

    Pour que l'automatisation soit réellement efficace, la stratégie de cache est cruciale. Voici ce que je configure systématiquement :

  • Cache-Control : public, max-age long (par ex. 30 jours) pour les images générées ; ajouter stale-while-revalidate pour réduire la latence pour le prochain visiteur,
  • ETag et Last-Modified : permettent aux CDN et navigateurs de valider et d'économiser de la bande passante,
  • invalidations : prévoir une route d'invalidation quand l'original change (webhook depuis le CMS ou le storage),
  • pré-génération : pour les images critiques ou les tailles fréquentes, je génère en amont (build time) pour éviter les cold starts.
  • Aspects opérationnels et coûts

    Il faut garder en tête que :

  • les fonctions serverless ont des limites de mémoire et temps d'exécution ; pour des images très volumineuses ou des transformations lourdes, il faut ajuster la configuration ou opter pour des workers/Edge Functions,
  • l'encodage AVIF peut être plus coûteux en CPU — pensez à benchmarker,
  • le cache CDN réduit fortement le nombre d'exécutions facturables : une fois en cache, la vignette est servie sans exécution supplémentaire,
  • je surveille l'usage et mets en place des limites pour éviter les abus (rate limiting, quotas par clé API si nécessaire).
  • Expérience pratique : erreurs courantes que j'ai vues

  • Ne pas valider les paramètres d'entrée : risque d'attaques qui forcent le traitement d'images énormes,
  • Oublier d'ajouter les headers Cache-Control et ETag, ce qui conduit à beaucoup de trafic inutiles,
  • Servir toujours le même format : il faut détecter l'accept header pour proposer AVIF/WebP quand le navigateur le supporte,
  • Ne pas prévoir de fallback : toujours servir un format universel quand nécessaire.
  • Si vous débutez, commencez par automatiser quelques tailles clés (ex. 320, 640, 1280, 1920) et proposer WebP en priorité. Ensuite, itérez en observant vos Core Web Vitals et vos analytics réseau. Pour mes sites, cette approche a souvent réduit le poids média de 40 à 70% et amélioré sensiblement le LCP.