Aller au contenu

API de Service d'images

astro:assets a été conçu pour permettre à n’importe quel service d’optimisation d’images de construire facilement un service au-dessus d’Astro.

Qu’est-ce qu’un service d’images ?

Astro propose deux types de services d’images : Local et Externe.

  • Les services locaux gèrent les transformations d’images directement lors de la construction pour les sites statiques, ou lors de l’exécution en mode développement et SSR. Ce sont souvent des enveloppes autour de bibliothèques comme Sharp, ImageMagick, ou Squoosh. En mode développement et en SSR, les services locaux utilisent un point de terminaison de l’API pour effectuer la transformation.
  • Les services externes pointent vers des URL et peuvent ajouter la prise en charge de services tels que Cloudinary, Vercel ou tout autre serveur conforme à RIAPI.

Construire à l’aide de l’API d’un service d’image

Les définitions de service prennent la forme d’un objet par défaut exporté avec diverses méthodes requises (“hooks”).

Les services externes fournissent un getURL() qui pointe vers le src de la balise <img> de sortie.

Les services locaux fournissent une méthode transform() pour effectuer des transformations sur votre image, et les méthodes getURL() et parseURL() pour utiliser un point de terminaison pour le mode dev et SSR.

Les deux types de services peuvent fournir getHTMLAttributes() pour déterminer les autres attributs de la sortie <img> et validateOptions() pour valider et augmenter les options passées.

Services Externes

Un service externe pointe vers une URL distante à utiliser comme attribut src de la balise <img> finale. Cette URL distante est responsable du téléchargement, de la transformation et du renvoi de l’image.

import type { ExternalImageService, ImageTransform, AstroConfig } from "astro";
const service: ExternalImageService = {
validateOptions(options: ImageTransform, imageConfig: AstroConfig['image']) {
const serviceConfig = imageConfig.service.config;
// Appliquer la largeur maximale définie par l'utilisateur.
if (options.width > serviceConfig.maxWidth) {
console.warn(`Image width ${options.width} exceeds max width ${serviceConfig.maxWidth}. Falling back to max width.`);
options.width = serviceConfig.maxWidth;
}
return options;
},
getURL(options, imageConfig) {
return `https://mysupercdn.com/${options.src}?q=${options.quality}&w=${options.width}&h=${options.height}`;
},
getHTMLAttributes(options, imageConfig) {
const { src, format, quality, ...attributes } = options;
return {
...attributes,
loading: options.loading ?? 'lazy',
decoding: options.decoding ?? 'async',
};
}
};
export default service;

Services Local

Pour créer votre propre service local, vous pouvez pointer vers le built-in point de terminaison (/_image), ou vous pouvez également créer votre propre point de terminaison qui peut appeler les méthodes du service.

import type { LocalImageService, AstroConfig } from "astro";
const service: LocalImageService = {
getURL(options: ImageTransform, imageConfig: AstroConfig['image']) {
const searchParams = new URLSearchParams();
searchParams.append('href', typeof options.src === "string" ? options.src : options.src.src);
options.width && searchParams.append('w', options.width.toString());
options.height && searchParams.append('h', options.height.toString());
options.quality && searchParams.append('q', options.quality.toString());
options.format && searchParams.append('f', options.format);
return `/my_custom_endpoint_that_transforms_images?${searchParams}`;
// Vous pouvez également utiliser le point de terminaison intégré, qui appellera vos fonctions parseURL et transform :
// retourne `/_image?${searchParams}`;
},
parseURL(url: URL, imageConfig) {
return {
src: params.get('href')!,
width: params.has('w') ? parseInt(params.get('w')!) : undefined,
height: params.has('h') ? parseInt(params.get('h')!) : undefined,
format: params.get('f'),
quality: params.get('q'),
};
},
transform(buffer: Uint8Array, options: { src: string, [key: string]: any }, imageConfig): { data: Uint8Array, format: OutputFormat } {
const { buffer } = mySuperLibraryThatEncodesImages(options);
return {
data: buffer,
format: options.format,
};
},
getHTMLAttributes(options, imageConfig) {
let targetWidth = options.width;
let targetHeight = options.height;
if (typeof options.src === "object") {
const aspectRatio = options.src.width / options.src.height;
if (targetHeight && !targetWidth) {
targetWidth = Math.round(targetHeight * aspectRatio);
} else if (targetWidth && !targetHeight) {
targetHeight = Math.round(targetWidth / aspectRatio);
}
}
const { src, width, height, format, quality, ...attributes } = options;
return {
...attributes,
width: targetWidth,
height: targetHeight,
loading: attributes.loading ?? 'lazy',
decoding: attributes.decoding ?? 'async',
};
}
};
export default service;

Au moment de la construction des sites statiques et des routes pré-rendues, <Image /> et getImage(options) appellent la fonction transform(). Elles passent les options soit par les attributs du composant, soit par un argument options. Les images transformées seront compilées dans un dossier dist/_astro.

En mode dev et en mode SSR, Astro ne sait pas à l’avance quelles images doivent être optimisées. Astro utilise un point d’accès GET (par défaut, /_image) pour traiter les images au moment de l’exécution. <Image /> et getImage() transmettent leurs options à getURL(), qui renvoie l’URL du point d’accès. Ensuite, le point d’accès appelle parseURL() et transmet les propriétés résultantes à transform().

getConfiguredImageService & imageConfig

Si vous implémentez votre propre point d’accès comme point d’accès Astro, vous pouvez utiliser getConfiguredImageService et imageConfg pour appeler les méthodes parseURL et transform de votre service et fournir la configuration de l’image.

Pour accéder à la configuration du service d’image (image.service.config (EN)), vous pouvez utiliser imageConfig.service.config.

src/api/my_custom_endpoint_that_transforms_images.ts
import type { APIRoute } from "astro";
import { getConfiguredImageService, imageConfig } from 'astro:assets';
export const GET: APIRoute = async ({ request }) => {
const imageService = await getConfiguredImageService();
const imageTransform = imageService.parseURL(new URL(request.url), imageConfig);
// ... récupère l'image à partir de imageTransform.src et la stocke dans inputBuffer
const { data, format } = await imageService.transform(inputBuffer, imageTransform, imageConfig);
return new Response(data, {
status: 200,
headers: {
'Content-Type': mime.getType(format) || ''
}
}
);
}

Voir le point de terminaison intégré pour un exemple complet.

Hooks

getURL()

Requis pour les services locaux et externes

getURL(options: ImageTransform, imageConfig: AstroConfig['image']): string

Pour les services locaux, ce hook renvoie l’URL du point d’accès qui génère votre image (en mode SSR et dev). Il n’est pas utilisé pendant la construction. Le point d’accès local vers lequel getURL() pointe peut appeler à la fois parseURL() et transform().

Pour les services externes, ce hook renvoie l’URL finale de l’image.

Pour les deux types de services, les options sont les propriétés passées par l’utilisateur comme attributs du composant <Image /> ou comme options de getImage(). Elles sont du type suivant :

export type ImageTransform = {
// Images importées par l'ESM | chemins d'accès aux images distantes/publiques
src: ImageMetadata | string;
width?: number;
height?: number;
widths?: number[] | undefined;
densities?: (number | `${number}x`)[] | undefined;
quality?: ImageQuality;
format?: OutputFormat;
alt?: string;
[key: string]: any;
};

parseURL()

Requis pour les services locaux ; indisponible pour les services externes

parseURL(url: URL, imageConfig: AstroConfig['image']): { src: string, [key: string]: any}

Ce hook analyse les URLs générées par getURL() en un objet avec les différentes propriétés à utiliser par transform (en SSR et en mode dev). Il n’est pas utilisé pendant la construction.

transform()

Requis pour les services locaux ; indisponible pour les services externes

transform(buffer: Uint8Array, options: { src: string, [key: string]: any }, imageConfig: AstroConfig['image']): { data: Uint8Array, format: OutputFormat }

Ce hook transforme et renvoie l’image et est appelé pendant la construction pour créer les fichiers d’actifs finaux.

Vous devez retourner un format pour vous assurer que le bon type MIME est servi aux utilisateurs en mode SSR et développement.

getHTMLAttributes()

Facultatif pour les services locaux et externes

getHTMLAttributes(options: ImageTransform, imageConfig: AstroConfig['image']): Record<string, any>

Ce hook renvoie tous les attributs supplémentaires utilisés pour rendre l’image en HTML, en fonction des paramètres passés par l’utilisateur (options).

getSrcSet()

Ajouté à la version : astro@3.3.0 Experimental

Facultatif pour les services locaux et externes

getSrcSet?: (options: ImageTransform, imageConfig: AstroConfig['image']): SrcSetValue[] | Promise<SrcSetValue[]>;

Ce hook génère plusieurs variantes de l’image spécifiée, par exemple, pour générer un attribut srcset sur une <img> ou source sur <picture>.

Ce hook retourne un tableau d’objets avec les propriétés suivantes :

export type SrcSetValue = {
transform: ImageTransform;
descriptor?: string;
attributes?: Record<string, any>;
};

validateOptions()

Facultatif pour les services locaux et externes

validateOptions(options: ImageTransform, imageConfig: AstroConfig['image']): ImageTransform

Ce hook vous permet de valider et d’augmenter les options passées par l’utilisateur. C’est utile pour définir des options par défaut, ou pour indiquer à l’utilisateur qu’un paramètre est nécessaire.

Voir comment validateOptions() est utilisé dans les services intégrés Astro.

Configuration de l’utilisateur

Configurez le service d’image à utiliser dans astro.config.mjs. La configuration prend la forme suivante :

astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
image: {
service: {
entrypoint: "votre-point-d’entrée", // 'astro/assets/services/squoosh' | 'astro/assets/services/sharp' | string,
config: {
// ... configuration spécifique au service. En option.
}
}
},
});