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 ?

Titre de la section 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’image directement lors de la création pour les sites statiques, ou lors de l’exécution, à la fois en mode développement et pour le rendu à la demande. Il s’agit souvent de wrappers autour de bibliothèques telles que Sharp, ImageMagick ou Squoosh. En mode développement et dans les routes de production rendues à la demande, les services locaux utilisent un point de terminaison 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

Titre de la section 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 lors du rendu à la demande.

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.

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;

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',
};
},
propertiesToHash: ['src', 'width', 'height', 'format', 'quality'],
};
export default service;

Au moment de la construction des sites statiques et des routes pré-rendues, <Image /> et getImage(options) appellent la fonction transform(). Ces derniers transmettent les options soit par les attributs du composant, soit par un argument options, respectivement. Les images transformées seront compilées dans un dossier dist/_astro. Leurs noms de fichiers contiendront un hachage des propriétés passées à propertiesToHash. Cette propriété est optionnelle et sera par défaut ['src', 'width', 'height', 'format', 'quality']. Si votre service d’image personnalisé a plus d’options qui modifient les images générées, ajoutez-les dans le tableau.

En mode développement et lors de l’utilisation d’un adaptateur pour effectuer le rendu à la demande, 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().

Si vous implémentez votre propre point d’accès comme point d’accès Astro, vous pouvez utiliser getConfiguredImageService et imageConfig 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), 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.

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 de terminaison qui génère votre image (pour le rendu à la demande et en mode 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;
};

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.

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 renvoyer un format pour garantir que le type MIME approprié est fourni aux utilisateurs pour le rendu à la demande et le mode de développement.

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).

Ajouté à la version : astro@3.3.0

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>;
};

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.

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/sharp' | string,
config: {
// ... configuration spécifique au service. En option.
}
}
},
});

Astro propose plusieurs fonctions d’assistance permettant de développer un service d’images personnalisé. Ces utilitaires peuvent être importés depuis astro/assets/utils :

import {
isRemoteAllowed,
matchHostname,
matchPathname,
matchPattern,
matchPort,
matchProtocol
} from "astro/assets/utils";

Type : (src: string, { domains, remotePatterns }: {domains: string[], remotePatterns: RemotePattern[] }): boolean

Ajouté à la version : astro@4.0.0

Détermine si une ressource distante donnée, identifiée par son URL source, est autorisée en fonction de domaines spécifiés et de modèles distants.

import { isRemoteAllowed } from 'astro/assets/utils';
const testImageURL = 'https://example.com/images/test.jpg';
const domains = ['example.com', 'anotherdomain.com'];
const remotePatterns = [
{ protocol: 'https', hostname: 'images.example.com', pathname: '/**' }, // Autoriser n'importe quel chemin sous ce nom d'hôte
];
const url = new URL(testImageURL);
const isAllowed = isRemoteAllowed(url.href, { domains, remotePatterns });
console.log(`L'image distante est-elle autorisée ? ${isAllowed}`);

Type : (url: URL, hostname?: string, allowWildcard = false): boolean

Ajouté à la version : astro@4.0.0

Fait correspondre le nom d’hôte d’une URL donnée à un nom d’hôte spécifié, avec prise en charge facultative des modèles génériques.

import { matchHostname } from 'astro/assets/utils';
const testURL = new URL('https://sub.example.com/path/to/resource');
// Exemple d'utilisation de matchHostname
const hostnameToMatch = 'example.com';
// Correspondance sans caractère générique
const isMatchWithoutWildcard = matchHostname(testURL, hostnameToMatch);
console.log(`Le nom d'hôte correspond-il sans caractère générique ? ${isMatchWithoutWildcard}`); // Sortie : false
// Correspondance avec un caractère générique
const isMatchWithWildcard = matchHostname(testURL, hostnameToMatch, true);
console.log(`Le nom d'hôte correspond-il avec un caractère générique ? ${isMatchWithWildcard}`); // Sortie : true

Type : (url: URL, pathname?: string, allowWildcard = false): boolean

Ajouté à la version : astro@4.0.0

Fait correspondre le chemin d’accès d’une URL donnée à un modèle spécifié, avec prise en charge facultative des caractères génériques.

import { matchPathname } from 'astro/assets/utils';
const testURL = new URL('https://example.com/images/photo.jpg');
// Exemple de chemin d'accès à faire correspondre
const pathnameToMatch = '/images/photo.jpg';
// Correspondance sans caractère générique
const isMatchWithoutWildcard = matchPathname(testURL, pathnameToMatch);
console.log(`Le nom du chemin correspond-il sans caractère générique ? ${isMatchWithoutWildcard}`); // Sortie : true
// Correspondance avec un caractère générique
const wildcardPathname = '/images/*';
const isMatchWithWildcard = matchPathname(testURL, wildcardPathname, true);
console.log(`Le nom du chemin correspond-il avec un caractère générique ? ${isMatchWithWildcard}`); // Sortie : true

Type : (url: URL, remotePattern: RemotePattern): boolean

Ajouté à la version : astro@4.0.0

Évalue si une URL donnée correspond au modèle distant spécifié en fonction du protocole, du nom d’hôte, du port et du chemin d’accès.

import { matchPattern } from 'astro/assets/utils';
const testURL = new URL('https://images.example.com/photos/test.jpg');
// Définir un modèle distant pour correspondre à l'URL
const remotePattern = {
protocol: 'https',
hostname: 'images.example.com',
pathname: '/photos/**', // Caractère générique pour autoriser tous les fichiers sous /photos/
port: '', // Facultatif : faites correspondre n'importe quel port ou laissez vide par défaut
};
// Vérifiez si l'URL correspond au modèle distant
const isPatternMatched = matchPattern(testURL, remotePattern);
console.log(`L'URL correspond-elle au modèle distant ? ${isPatternMatched}`); // Sortie : true

Type : (url: URL, port?: string): boolean

Ajouté à la version : astro@4.0.0

Vérifie si le port de l’URL donnée correspond au port spécifié. Si aucun port n’est fourni, renvoie true.

import { matchPort } from 'astro/assets/utils';
const testURL1 = new URL('https://example.com:8080/resource');
const testURL2 = new URL('https://example.com/resource');
// Exemple d'utilisation de matchPort
const portToMatch = '8080';
// Faire correspondre une URL avec un port spécifié
const isPortMatch1 = matchPort(testURL1, portToMatch);
console.log(`Le port correspond-il ? ${isPortMatch1}`); // Sortie : true
// Faire correspondre une URL sans port spécifié (le port par défaut sera supposé)
const isPortMatch2 = matchPort(testURL2, portToMatch);
console.log(`Le port correspond-il ? ${isPortMatch2}`); // Sortie : false
// Vérifier une URL sans fournir explicitement de port (la valeur par défaut est true si le port n'est pas défini)
const isPortMatch3 = matchPort(testURL1);
console.log(`Le port correspond-il (aucun port spécifié) ? ${isPortMatch3}`); // Sortie : true

Type : (url: URL, protocol?: string): boolean

Ajouté à la version : astro@4.0.0

Compare le protocole de l’URL fournie avec un protocole spécifié.

import { matchProtocol } from 'astro/assets/utils';
const testURL1 = new URL('https://example.com/resource');
const testURL2 = new URL('http://example.com/resource');
// Exemple d'utilisation de matchProtocol
const protocolToMatch = 'https';
// Faire correspondre une URL avec le bon protocole
const isProtocolMatch1 = matchProtocol(testURL1, protocolToMatch);
console.log(`Le protocole correspond-il pour testURL1 ? ${isProtocolMatch1}`); // Sortie : true
// Faire correspondre une URL avec un protocole incorrect
const isProtocolMatch2 = matchProtocol(testURL2, protocolToMatch);
console.log(`Le protocole correspond-il pour testURL2? ${isProtocolMatch2}`); // Sortie : false
// Faire correspondre une URL sans fournir explicitement de protocole (la valeur par défaut est true si le protocole n'est pas défini)
const isProtocolMatch3 = matchProtocol(testURL1);
console.log(`Le protocole correspond-il (aucun protocole spécifié) ? ${isProtocolMatch3}`); // Sortie : true
Contribuer Communauté Parrainer
京ICP备15031610号-99