Optimisation des images
Le bext peut optimiser les images à la volée sans prétraitement de temps de construction. Le
Le plugin image_optimization expose un point de terminaison /api/image qui récupère une image source distante, la redimensionne à la largeur demandée, la recompresse et sert le résultat à partir d'un cache en mémoire. Les fichiers originaux ne sont jamais modifiés.
Configuration#
Activez et réglez le plugin dans la section [plugins.image_optimization] de
bext.config.toml. Le plugin est désactivé par défaut ; définissez enabled = true pour enregistrer l'itinéraire /api/image.
[plugins.image_optimization]
enabled = true
# Widths a client may request via `?w=`. A request for any other width is
# rejected with 400. (Default shown below.)
allowed_widths = [16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]
default_quality = 75 # Quality (1-100) used when `?q=` is omitted
max_source_bytes = 10485760 # Reject source images larger than this (default 10 MiB)
cache_max_entries = 5000 # Max optimized variants held in the in-memory LRU
cache_ttl_ms = 86400000 # Cache entry TTL in milliseconds (default 24h)
Tous les champs sont facultatifs et reviennent aux valeurs par défaut indiquées ci-dessus ( enabled est par défaut false ).
API des paramètres de requête#
Le point de terminaison /api/image prend l'image source comme paramètre de requête url et les options de transformation qui l'accompagnent :
/api/image?url=https%3A%2F%2Fexample.com%2Fhero.jpg&w=800&q=75
| Paramètre | Description | Défaut |
|---|---|---|
url |
URL de l'image source codée en URL (obligatoire, HTTPS uniquement ) | — |
w |
Largeur cible en pixels — doit être une valeur dans allowed_widths (obligatoire) |
— |
q |
Qualité (1-100) | default_quality (75) |
L'URL source doit être https:// et ne doit pas être résolue vers un hôte privé ou de bouclage (protection SSRF) ; l'optimiseur ne suit également aucune redirection. Les requêtes qui omettent url, omettent w ou utilisent une largeur en dehors de allowed_widths renvoient 400.
Exemples#
# Resize a remote image to 640px wide at quality 75 (output format negotiated
# from the Accept header — see below)
curl 'https://example.com/api/image?url=https%3A%2F%2Fcdn.example.com%2Fphoto.jpg&w=640&q=75'
Négociation de formats#
Le plugin lit l'en-tête de la requête Accept et sélectionne automatiquement le format de sortie — il n'y a pas de paramètre de requête format. L'ordre de préférence est WebP, puis PNG (uniquement si le client annonce image/png mais pas WebP), sinon JPEG :
| Accepter l'en-tête contient | Format servi |
|---|---|
image/webp |
WebP |
image/png (et non WebP) |
PNG |
| Ni l'un ni l'autre | JPEG (repli) |
Cela signifie que vous pouvez pointer un seul <img> vers /api/image et laisser bext choisir le format :
<img src="/api/image?url=https%3A%2F%2Fcdn.example.com%2Fhero.jpg&w=800" alt="Hero image" />
<!-- Browsers that advertise WebP receive WebP; others receive JPEG -->
Remarque : ce plugin négocie WebP / PNG / JPEG. AVIF n'est pas produit par le plugin
image_optimization.
Génération de Srcset#
Pour les images réactives, créez un srcset en pointant chaque candidat vers une valeur ?w= différente (chaque largeur doit être dans allowed_widths ). Chaque entrée se résout en une image optimisée indépendamment :
<img
srcset="/api/image?url=https%3A%2F%2Fcdn.example.com%2Fhero.jpg&w=640 640w,
/api/image?url=https%3A%2F%2Fcdn.example.com%2Fhero.jpg&w=1080 1080w,
/api/image?url=https%3A%2F%2Fcdn.example.com%2Fhero.jpg&w=1920 1920w"
sizes="(max-width: 640px) 100vw, 50vw"
src="/api/image?url=https%3A%2F%2Fcdn.example.com%2Fhero.jpg&w=1080"
alt="Hero image"
loading="lazy"
/>
Comportement du cache#
Les variantes optimisées sont conservées dans un cache LRU en mémoire, délimité par
cache_max_entries et a expiré après cache_ttl_ms. Un accès au cache est renvoyé immédiatement et la réponse contient x-bext-image-cache: hit. Les réponses réussies sont envoyées avec cache-control: public, max-age=86400, immutable afin que les CDN et les navigateurs en aval les mettent également en cache.
La clé de cache est dérivée d'un hachage de l'URL source combiné avec la largeur, la qualité et le format négocié :
{xxhash64_hex}/{width}/q{quality}.{ext}
# Example: a1b2c3d4e5f67890/800/q75.webp
Conseils de performances#
- Définir des largeurs explicites – éviter de diffuser l'image d'origine de 4 000 px sur mobile
clients. Un
?w=640permet d'économiser une bande passante importante. Gardez leallowed_widthsproche des tailles que vous utilisez réellement. - S'appuyer sur WebP -- le plugin sert automatiquement WebP aux clients qui faites-en la publicité, généralement 25 à 35 % plus petit que le JPEG à qualité équivalente.
- Préchauffer les images populaires -- demander les URL
/api/imagepopulaires après un redémarrez pour amorcer le cache en mémoire. - Ajuster la qualité -- pour les images de héros,
q=80est une bonne valeur par défaut. Pour miniatures,q=60est souvent impossible à distinguer et nettement plus petit.
Le plugin est désactivé par défaut ( enabled = false ). Sans enabled = true dans [plugins.image_optimization], la route /api/image n'est jamais enregistrée et toutes les demandes renvoient 404.
Le cache LRU en mémoire est réinitialisé au redémarrage du serveur. Si vous comptez sur l'optimisation des images pour les itinéraires à fort trafic, utilisez cache::warm (voir Planificateur de tâches ) pour pré-remplir le cache après un déploiement.
En rapport#
- Mise en cache : comment le cache hiérarchisé partagé fonctionne avec l'image LRU
- Utilitaires de référencement — La génération d'images OG utilise le même pipeline d'optimisation
- Planificateur de tâches – planifier le réchauffement du cache après le déploiement pour les URL d'images populaires
- Référence de configuration — liste complète des champs
bext.config.toml - Compression — Brotli/gzip pour les ressources texte ; les images utilisent ce plugin à la place