Aller au contenu

Astro Integration API

Les intégrations d’Astro ajoutent de nouvelles fonctionnalités et de nouveaux comportements à votre projet avec seulement quelques lignes de code.

Cette page de référence est destinée aux personnes qui écrivent leur propre intégration. Pour apprendre à utiliser une intégration dans votre projet, consultez plutôt notre guide sur l’utilisation des intégrations.

Les intégrations officielles d’Astro peuvent vous servir de référence pour construire vos propres intégrations.

interface AstroIntegration {
name: string;
hooks: {
'astro:config:setup'?: (options: {
config: AstroConfig;
command: 'dev' | 'build' | 'preview';
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
addClientDirective: (directive: ClientDirectiveConfig) => void;
addMiddleware: (middleware: AstroIntegrationMiddleware) => void;
addDevToolbarApp: (pluginEntrypoint: string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: ({ pattern: string, entrypoint: string }) => void;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:config:done'?: (options: { config: AstroConfig; setAdapter: (adapter: AstroAdapter) => void; logger: AstroIntegrationLogger; }) => void | Promise<void>;
'astro:server:setup'?: (options: { server: vite.ViteDevServer; logger: AstroIntegrationLogger; }) => void | Promise<void>;
'astro:server:start'?: (options: { address: AddressInfo; logger: AstroIntegrationLogger; }) => void | Promise<void>;
'astro:server:done'?: (options: { logger: AstroIntegrationLogger; }) => void | Promise<void>;
'astro:build:start'?: (options: { logger: AstroIntegrationLogger; }) => void | Promise<void>;
'astro:build:setup'?: (options: {
vite: ViteConfigWithSSR;
pages: Map<string, PageBuildData>;
target: 'client' | 'server';
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:generated'?: (options: { dir: URL; logger: AstroIntegrationLogger; }) => void | Promise<void>;
'astro:build:ssr'?: (options: {
manifest: SerializedSSRManifest;
entryPoints: Map<RouteData, URL>;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:done'?: (options: { dir: URL; routes: RouteData[]; logger: AstroIntegrationLogger; }) => void | Promise<void>;
};
}

Prochain hook : astro:config:done

Quand : Lors de l’initialisation, avant que les configurations de Vite ou d’Astro ne soient résolues.

Pourquoi : Pour étendre la configuration du projet. Cela comprend la mise à jour de la configuration Astro, l’application des plugins Vite, l’ajout de moteurs de rendu de composants et l’injection de scripts dans la page.

'astro:config:setup'?: (options: {
config: AstroConfig;
command: 'dev' | 'build' | 'preview';
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addClientDirective: (directive: ClientDirectiveConfig) => void;
addMiddleware: (middleware: AstroIntegrationMiddleware) => void;
addDevToolbarApp: (pluginEntrypoint: string) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: ({ pattern: string, entrypoint: string }) => void;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;

Type : AstroConfig

Une copie en lecture seule de la configuration Astro fournie par l’utilisateur. Ceci est résolu avant que toutes les autres intégrations aient été exécutées. Si vous avez besoin d’une copie de la configuration après que toutes les intégrations ont terminé leurs mises à jour, consultez le hook astro:config:done.

Type : 'dev' | 'build' | 'preview'

  • dev - Le projet est exécuté avec astro dev
  • build - Le projet est executé avec astro build
  • preview - Le projet est executé avec astro preview

Type : boolean

false lorsque le serveur de développement démarre, true lorsqu’un rechargement est déclenché. Utile pour détecter si cette fonction est appelée plus d’une fois.

Type : (newConfig: DeepPartial<AstroConfig>) => AstroConfig;

Une fonction de callback pour mettre à jour la config d’Astro fournie par l’utilisateur. Toute configuration que vous fournissez sera fusionnée avec la configuration de l’utilisateur + les mises à jour effectuées par d’autres intégrations, vous êtes donc libre d’ignorer les clés !

Par exemple, disons que vous devez fournir un plugin Vite au projet de l’utilisateur :

import bananaCSS from '@vitejs/official-banana-css-plugin';
export default {
name: 'banana-css-integration',
hooks: {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
vite: {
plugins: [bananaCSS()],
}
})
}
}
}

Type : (renderer: AstroRenderer ) => void; Exemples : lit, svelte, react, preact, vue, solid

Une fonction de callback pour ajouter un framework de composants (c’est-à-dire React, Vue, Svelte, etc). Vous pouvez consulter les exemples et la définition des types ci-dessus pour des options plus avancées, mais voici les deux principales options à connaître :

  • clientEntrypoint - chemin d’accès à un fichier qui s’exécute sur le client chaque fois que votre composant est utilisé. Ce fichier sert principalement à afficher ou à hydrater votre composant avec JS.
  • serverEntrypoint - chemin d’accès à un fichier qui s’exécute lors des requêtes côté serveur ou des constructions statiques chaque fois que votre composant est utilisé. Ceux-ci devraient afficher les composants en balisage statique, avec des crochets pour l’hydratation le cas échéant. Le callback renderToString de React est un exemple classique.

Type : URL | string

Si votre intégration dépend d’un fichier de configuration que Vite ne surveille pas et/ou qui nécessite un redémarrage complet du serveur de développement pour prendre effet, ajoutez-le avec addWatchFile. Chaque fois que ce fichier changera, le serveur de développement Astro sera rechargé (vous pouvez vérifier quand un rechargement a lieu avec isRestart).

Exemple d’utilisation :

// Il doit s'agir d'un chemin d'accès absolu !
addWatchFile('/home/user/.../my-config.json');
addWatchFile(new URL('./tailwind.config.js', config.root));

Ajouté à la version : astro@2.6.0

Type : (directive: ClientDirectiveConfig ) => void;

Ajoute une directive client personnalisée à utiliser dans les fichiers .astro.

Notez que les points d’entrée des directives ne sont intégrés qu’à travers esbuild et qu’ils doivent rester petits afin de ne pas ralentir l’hydratation des composants.

Exemple d’utilisation :

astro.config.mjs
import { defineConfig } from 'astro/config';
import clickDirective from './astro-click-directive/register.js'
// https://astro.build/config
export default defineConfig({
integrations: [
clickDirective()
],
});
astro-click-directive/register.js
/**
* @type {() => import('astro').AstroIntegration}
*/
export default () => ({
name: "client:click",
hooks: {
"astro:config:setup": ({ addClientDirective }) => {
addClientDirective({
name: "click",
entrypoint: "./astro-click-directive/click.js",
});
},
},
});
astro-click-directive/click.js
/**
* hydrate au premier clic sur la fenêtre
* @type {import('astro').ClientDirective}
*/
export default (load, opts, el) => {
window.addEventListener('click', async () => {
const hydrate = await load()
await hydrate()
}, { once: true })
}

Vous pouvez également ajouter des types pour les directives dans le fichier de définition des types de votre bibliothèque :

astro-click-directive/index.d.ts
import 'astro'
declare module 'astro' {
interface AstroClientDirectives {
'client:click'?: boolean
}
}

Ajouté à la version : astro@3.4.0

Type: (pluginEntrypoint: string) => void;

Ajoute une application de barre d’outils de développement personnalisée.

Exemple d’utilisation :

astro.config.mjs
import { defineConfig } from 'astro/config';
import devToolbarIntegration from './astro-dev-toolbar-app/integration.js'
// https://astro.build/config
export default defineConfig({
integrations: [
devToolbarIntegration()
],
});
astro-dev-toolbar-app/integration.js
/**
* @type {() => import('astro').AstroIntegration}
*/
export default () => ({
name: "dev-toolbar-app",
hooks: {
"astro:config:setup": ({ addDevToolbarApp }) => {
addDevToolbarApp("./astro-dev-toolbar-app/plugin.js");
},
},
});
astro-dev-toolbar-app/plugin.js
/**
* @type {import('astro').DevToolbarApp}
*/
export default {
id: "my-plugin",
name: "My Plugin",
icon: "<svg>...</svg>",
init() {
console.log("I'm a dev toolbar app!")
},
};

Ajouté à la version : astro@3.5.0

Type : (middleware: AstroIntegrationMiddleware ) => void;

Ajoute un middleware à exécuter sur chaque requête. Prend le module entrypoint qui contient le middleware, et un order pour spécifier s’il doit s’exécuter avant (pre) d’autres middlewares ou après (post).

@my-package/integration.js
/**
* @type {() => import('astro').AstroIntegration}
*/
export default () => ({
name: "my-middleware-package",
hooks: {
"astro:config:setup": ({ addMiddleware }) => {
addMiddleware({
entrypoint: '@my-package/middleware',
order: 'pre'
});
},
},
});

Le middleware est défini dans un paquetage avec une fonction onRequest, comme pour le middleware défini par l’utilisateur.

@my-package/middleware.js
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
if(context.url.pathname === '/some-test-path') {
return Response.json({
ok: true
});
}
return next();
});

Type : ({ pattern: string, entrypoint: string }) => void;

Une fonction de rappel pour injecter des routes dans un projet Astro. Les routes injectées peuvent être des pages .astro ou des gestionnaires de routes .js et .ts.

injectRoute prend un objet avec un pattern et un entrypoint.

  • pattern - lorsque la route doit être affichée dans le navigateur, par exemple /foo/bar. Un pattern peut utiliser la syntaxe de chemin de fichier d’Astro pour indiquer des routes dynamiques, par exemple /foo/[bar] ou /foo/[...bar]. Notez qu’une extension de fichier n’est pas nécessaire dans le pattern.
  • entrypoint - un spécificateur de module nu pointant vers la page .astro ou le gestionnaire de route .js/.ts qui gère la route indiquée dans le pattern.
injectRoute({
// Utilise la syntaxe Astro pour les itinéraires dynamiques.
pattern: '/subfolder/[dynamic]',
// Utilise la syntaxe du chemin relatif pour une route locale.
entrypoint: './src/dynamic-page.astro'
});

Pour une intégration conçue pour être installée dans d’autres projets, utilisez son nom de paquetage pour faire référence au point d’entrée de la route. L’exemple suivant montre un paquet publié sur npm sous le nom @fancy/dashboard injectant une route de tableau de bord :

injectRoute({
pattern: '/fancy-dashboard',
entrypoint: '@fancy/dashboard/dashboard.astro'
});

Lorsque vous publiez votre paquet (@fancy/dashboard, dans ce cas) sur npm, vous devez exporter dashboard.astro dans votre package.json :

package.json
{
"name": "@fancy/dashboard",
// ...
"exports": { "./dashboard.astro": "./dashboard.astro" }
}

Type : (stage: InjectedScriptStage, content: string) => void;

Une fonction de rappel pour injecter une chaîne de contenu JavaScript sur chaque page.

Le stage indique comment ce script (le contenu) doit être inséré. Certaines étapes permettent d’insérer des scripts sans modification, tandis que d’autres permettent une optimisation pendant l’étape de regroupement de Vite :

  • "head-inline": Injecté dans une balise script dans le <head> de chaque page. Non optimisé ou interprété par Vite.
  • "before-hydration": Importé côté client, avant l’exécution du script d’hydratation. Optimisé et interprété par Vite.
  • "page": Similaire à head-inline, sauf que l’extrait injecté est traité par Vite et regroupé avec toutes les autres balises <script> définies à l’intérieur des composants Astro sur la page. Le script sera chargé avec un <script type="module"> dans la sortie finale de la page, optimisé et interprété par Vite.
  • "page-ssr": Importé en tant que module séparé dans le frontmatter de chaque composant de page Astro. Parce que cette étape importe votre script, le global Astro n’est pas disponible et votre script ne sera exécuté qu’une seule fois lorsque l’instruction import est évalué pour la première fois.

La principale utilisation de l’étape page-ssr est l’injection d’un import CSS dans chaque page à optimiser et à résoudre par Vite :

injectScript('page-ssr', 'import "global-styles.css";');

Hook précédent : astro:config:setup

Hook suivant : astro:server:setup en mode “dev”, ou astro:build:start en mode “production”.

Quand : Après que la configuration Astro a été résolue et que les autres intégrations aient exécuté leurs crochets astro:config:setup.

Pourquoi : Pour récupérer la configuration finale afin de l’utiliser dans d’autres hooks.

'astro:config:done'?: (options: { config: AstroConfig }) => void | Promise<void>;

Type : AstroConfig

Une copie en lecture seule de la configuration Astro fournie par l’utilisateur. Ce problème est résolu après l’exécution des autres intégrations.

Hook précédent : astro:config:done

Hook suivant : astro:server:start

Quand : Juste après la création du serveur Vite en mode “dev”, mais avant que l’événement listen() ne soit déclenché. Voir l’API createServer de Vite pour plus d’informations.

Pourquoi : Pour mettre à jour les options du serveur Vite et le middleware.

'astro:server:setup'?: (options: { server: vite.ViteDevServer }) => void | Promise<void>;

Type : ViteDevServer

Une instance mutable du serveur Vite utilisée en mode “dev”. Par exemple, c’est utilisé par notre intégration Partytown pour injecter le serveur Partytown en tant que middleware :

export default {
name: 'partytown',
hooks: {
'astro:server:setup': ({ server }) => {
server.middlewares.use(
function middleware(req, res, next) {
// traite les demandes
}
);
}
}
}

Hook précédent : astro:server:setup

Hook suivant : astro:server:done

Quand : Juste après que l’événement listen() du serveur se soit déclenché.

Pourquoi : Intercepter les requêtes réseau à l’adresse spécifiée. Si vous avez l’intention d’utiliser cette adresse pour un middleware, pensez à utiliser astro:server:setup à la place.

'astro:server:start'?: (options: { address: AddressInfo }) => void | Promise<void>;

Type : AddressInfo

L’adresse, la famille et le numéro de port fournis par le module Node.js Net.

Hook précédent : astro:server:start

Quand : Juste après la fermeture du serveur de développement.

Pourquoi : Pour exécuter les événements de nettoyage que vous pouvez déclencher pendant les hooks astro:server:setup ou astro:server:start.

'astro:server:done'?: () => void | Promise<void>;

Hook précédent : astro:config:done

Hook suivant : astro:build:setup

Quand : Après l’événement astro:config:done, mais avant le début de la construction de la production.

Pourquoi : Pour configurer les objets globaux ou les clients nécessaires lors d’une construction de production. Cela peut également étendre les options de configuration de la construction dans l’API d’adaptateur.

'astro:build:start'?: () => void | Promise<void>;

Hook précédent : astro:build:start

Hook suivant : astro:build:ssr

Quand : Après le crochet astro:build:start, s’exécute immédiatement avant la construction.

Pourquoi : A ce stade, la configuration de Vite pour la construction a été complètement construite, c’est votre dernière chance de la modifier. Cela peut être utile, par exemple, pour écraser certains paramètres par défaut. Si vous n’êtes pas sûr de devoir utiliser ce crochet ou astro:build:start, utilisez plutôt astro:build:start.

'astro:build:setup'?: (options: {
vite: ViteConfigWithSSR;
pages: Map<string, PageBuildData>;
target: 'client' | 'server';
}) => void | Promise<void>;

Hook précédent : astro:build:setup

Quand : Une fois qu’une version statique de production a fini de générer des itinéraires et des ressources.

Pourquoi : Accéder aux routes et aux ressources générées avant que les artefacts de construction ne soient nettoyés. C’est un cas d’utilisation très rare. Nous recommandons d’utiliser astro:build:done à moins que vous n’ayez vraiment besoin d’accéder aux fichiers générés avant le nettoyage.

'astro:build:generated'?: (options: { dir: URL }) => void | Promise<void>;

Hook précédent : astro:build:setup

Quand : Après la construction d’un SSR en production.

Pourquoi : Pour accéder au manifeste SSR et à la carte des points d’entrée émis. Ceci est utile lors de la création de SSR personnalisés dans des plugins ou des intégrations.

  • entryPoints fait correspondre une route de page au fichier physique émis après la construction ;
  • middlewareEntryPoint est le chemin d’accès au système de fichiers du middleware ;
'astro:build:ssr'?: (options: {
manifest: SerializedSSRManifest,
entryPoints: Map<RouteData, URL>,
middlewareEntryPoint: URL
}) => void | Promise<void>;

Hook précédent :astro:build:ssr

Quand : Après l’achèvement d’une construction de production (SSG ou SSR).

Pourquoi : Pour accéder aux routes et aux actifs générés pour l’extension (ex. copier le contenu dans le répertoire /assets généré). Si vous envisagez de transformer les actifs générés, nous vous recommandons d’explorer Vite Plugin API et configurer via astro:config:setup à la place.

'astro:build:done'?: (options: { dir: URL; routes: RouteData[], pages: { pathname: string }[] }) => void | Promise<void>;

Type : URL

Un chemin URL vers le répertoire de sortie de la compilation. Notez que si vous avez besoin d’un chemin absolu valide, vous devriez utiliser l’utilitaire intégré de Node fileURLToPath.

import { writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
export default function myIntegration() {
return {
hooks: {
'astro:build:done': async ({ dir }) => {
const metadata = await getIntegrationMetadata();
// Utilisez fileURLToPath pour obtenir une chaîne de chemin absolu valide et multiplateforme.
const outFile = fileURLToPath(new URL('./my-integration.json', dir));
await writeFile(outFile, JSON.stringify(metadata));
}
}
}
}

Type : RouteData[]

Une liste de tous les itinéraires générés avec leurs métadonnées associées.

Vous pouvez référencer le type RouteData complet ci-dessous, mais les propriétés les plus courantes sont les suivantes :

  • component - le chemin du fichier d’entrée par rapport à la racine du projet
  • pathname - l’URL du fichier de sortie (non définie pour les routes utilisant les paramètres [dynamic] et [...spread])
interface RouteData {
/** Si une route donnée est une page HTML ou un point d'arrivée non HTML */
type: 'page' | 'endpoint';
/** Source component URL */
component: string;
/**
* Chemin d'accès à l'URL de sortie lorsque cette route sera servie
* note: sera indéfini pour les itinéraires [dynamic] et [...spread].
*/
pathname?: string;
/**
* regex utilisée pour faire correspondre une URL d'entrée à une route demandée
* ex. "[fruit]/about.astro" génère le modèle: /^\/([^/]+?)\/about\/?$/
* lorsque pattern.test("banana/about") est "true"
*/
pattern: RegExp;
/**
* Paramètres des itinéraires dynamiques et étendus
* ex. "/pages/[lang]/[..slug].astro" affichera les paramètres ['lang', '...slug']
*/
params: string[];
/**
* Similaire au champ "params", mais avec plus de métadonnées associées.
* ex. "/pages/[lang]/index.astro" produira les segments suivants
* [[ { content: 'lang', dynamic: true, spread: false } ]]
*/
segments: { content: string; dynamic: boolean; spread: boolean; }[][];
/**
* Fonction permettant d'afficher le composant sur place à partir d'un ensemble de données d'entrée.
* Il s'agit généralement d'un usage interne, à utiliser avec précaution !
*/
generate: (data?: any) => string;
}

Type : { pathname: string }[]

Une liste de toutes les pages générées. Il s’agit d’un objet avec une propriété.

  • pathname - le chemin finalisé de la page.

Autoriser l’installation avec astro add

Titre de la section Autoriser l’installation avec astro add

La commande astro add permet aux utilisateurs d’ajouter facilement des intégrations et des adaptateurs à leur projet. Si vous voulez que votre intégration soit installable avec cet outil, ajoutez astro-integration au champ keywords dans votre package.json :

{
"name": "example",
"keywords": ["astro-integration"],
}

Une fois que vous avez publié votre intégration sur npm, lancer astro add example installera votre paquet avec toutes les dépendances spécifiées dans votre package.json. Cela appliquera également votre intégration au astro.config de l’utilisateur comme suit :

astro.config.mjs
import { defineConfig } from 'astro/config';
import example from 'example';
export default defineConfig({
integrations: [example()],
})

Une instance du logger Astro, utile pour écrire des logs. Ce logger utilise le même niveau de log configuré via le CLI.

Méthodes disponibles pour écrire dans le terminal :

  • logger.info("Message");
  • logger.warn("Message");
  • logger.error("Message");
  • logger.debug("Message");

Méthodes disponibles pour écrire dans le terminal :

integration.ts
import type { AstroIntegration } from "astro";
export function formatIntegration(): AstroIntegration {
return {
name: "astro-format",
hooks: {
"astro:build:done": ({ logger }) => {
// fait quelque chose
logger.info("Integration ready.");
}
}
}
}

L’exemple ci-dessus enregistre un message qui comprend le message info fourni :

Fenêtre de terminal
[astro-format] Integration ready.

Pour enregistrer certains messages avec un libellé différent, utilisez la méthode .fork pour spécifier une alternative au name par défaut :

integration.ts
import type { AstroIntegration } from "astro";
export function formatIntegration(): AstroIntegration {
return {
name: "astro-format",
hooks: {
"astro:config:done": ({ logger }) => {
// fait quelque chose
logger.info("Integration ready.");
},
"astro:build:done": ({ logger }) => {
const buildLogger = logger.fork("astro-format/build");
// fait quelque chose
buildLogger.info("Build finished.")
}
}
}
}

L’exemple ci-dessus produira des journaux avec [astro-format] par défaut, et [astro-format/build] si spécifié :

Fenêtre de terminal
[astro-format] Integration ready.
[astro-format/build] Build finished.

Toutes les intégrations sont exécutées dans l’ordre dans lequel elles sont configurées. Par exemple, pour le tableau [react(), svelte()] dans le fichier astro.config.* d’un utilisateur, react s’exécutera avant svelte.

Votre intégration devrait idéalement s’exécuter dans n’importe quel ordre. Si ce n’est pas possible, nous recommandons de documenter que votre intégration doit venir en premier ou en dernier dans le tableau de configuration integrations de votre utilisateur.

Combiner les intégrations dans des préréglages

Titre de la section Combiner les intégrations dans des préréglages

Une intégration peut également être décrite comme une collection de plusieurs intégrations plus petites. Au lieu de créer une fonction d’usine qui renvoie un objet d’intégration unique, nous appelons ces collections présets, un preset renvoie un array d’objets d’intégration. Cette fonction est utile pour créer des fonctionnalités complexes à partir de plusieurs intégrations.

integrations: [
// Exemple: lorsque examplePreset() retourne : [integrationOne, integrationTwo, ...etc]
examplePreset()
]