Que fait Architecte d'îles Astro ?
Astro, c'est « livrer du HTML par défaut, n'hydrater que ce qui nécessite du JS ». Pour les sites marketing, de documentation et les sites riches en contenu, cela produit des bundles bien plus petits qu'avec React/Next.js. Tout le jeu consiste à choisir quels composants sont statiques et lesquels sont des îles.
Quand l'utiliser
- Site marketing, blog, portail de documentation — le contenu est le produit.
- Migration depuis un site marketing Next.js qui est trop lourd en JS côté client.
- Multi-framework — une bibliothèque de composants React utilisée aux côtés de composants Vue ou Svelte.
- Création de contenu intensive avec MDX + frontmatter typé.
- Transitions de vue entre les pages sans SPA.
Capacités principales
Structure de page
---
// src/pages/blog/[slug].astro — le frontmatter s'exécute au moment de la construction/SSR
import { getCollection, getEntry } from 'astro:content';
import Layout from '../../layouts/Default.astro';
import Newsletter from '../../components/Newsletter.tsx';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((p) => ({ params: { slug: p.slug }, props: { post: p } }));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<Layout title={post.data.title}>
<h1>{post.data.title}</h1>
<article><Content /></article>
{/* Île — seul ce composant livre du JS */}
<Newsletter client:visible />
</Layout>
Les délimiteurs --- sont du code serveur. À l'intérieur de <...>, le contenu par défaut est du HTML statique. Les composants avec des directives client:* deviennent des îles.
Directives client — choisissez la bonne
| Directive | Moment de l'hydratation | Utilisation |
|---|---|---|
client:load | Chargement de la page | Interactif visible sans défilement (panier, recherche). |
client:idle | Lorsque le navigateur est inactif | Interactif non critique (widget de chat). |
client:visible | Lorsque l'élément défile dans la zone visible | Contenu en bas de page (inscription à la newsletter, commentaires). |
client:media="(min-width: 768px)" | Lorsque la requête média correspond | Widgets uniquement pour ordinateur de bureau. |
client:only="react" | Ignorer le SSR ; rendu côté client uniquement | Composants nécessitant des API navigateur au montage. |
client:idle est la valeur par défaut appropriée pour la plupart des îles non critiques. client:load est le marteau lourd ; réservez-le.
Collections de contenu
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content', // fichiers markdown/MDX
schema: z.object({
title: z.string().max(120),
description: z.string().max(160),
date: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
cover: z.object({ src: z.string(), alt: z.string() }).optional(),
}),
});
export const collections = { blog };
Maintenant, getCollection('blog') est entièrement typé. Les erreurs de frontmatter font échouer la construction, pas la production.
const posts = (await getCollection('blog'))
.filter((p) => !p.data.draft)
.sort((a, b) => +b.data.date - +a.data.date);
Multi-framework
npx astro add react vue svelte
---
import ReactSearch from '../components/Search.tsx';
import VueChart from '../components/Chart.vue';
import SvelteToggle from '../components/Toggle.svelte';
---
<ReactSearch client:idle />
<VueChart client:visible />
<SvelteToggle client:load />
Le runtime de chaque framework est regroupé séparément et chargé uniquement sur les pages qui l'utilisent. Pour un site de documentation principalement statique, cela peut signifier ne livrer aucun JS React à la plupart des pages.
Îles serveur (Astro 4+)
<Layout>
<Header />
<PersonalizedRecommendations server:defer>
<p slot="fallback">Chargement des recommandations...</p>
</PersonalizedRecommendations>
<Footer />
</Layout>
server:defer rend le reste de la page immédiatement et diffuse le HTML du composant différé via une requête séparée. Utile pour le contenu personnalisé qui forcerait autrement toute la page à être en SSR.
Optimisation des images
---
import { Image } from 'astro:assets';
import cover from '../assets/cover.jpg';
---
<Image src={cover} alt="Photo de couverture" widths={[400, 800, 1200]} sizes="(max-width: 768px) 400px, 1200px" />
Astro génère srcset, exécute Sharp pour le redimensionnement, et ne livre que ce qui est nécessaire. Placez les images sous src/assets/ pour une optimisation complète ; public/ n'est pas traité.
Transitions de vue
---
import { ViewTransitions } from 'astro:transitions';
---
<html>
<head>
<ViewTransitions />
</head>
...
</html>
<a href="/about" transition:name="hero">À propos</a>
Transitions entre pages sans SPA. Le navigateur fait la majeure partie du travail ; Astro coordonne la correspondance des éléments.
MDX avec composants
---
title: Mon article
date: 2026-04-30
---
import Callout from '../../components/Callout.astro';
# {frontmatter.title}
<Callout type="warn">
Ceci est un avertissement rendu côté serveur. Aucun JS.
</Callout>
Les composants importés dans MDX s'exécutent au moment de la construction/SSR, sauf s'il s'agit d'îles.
SSR hybride
// astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'hybrid',
adapter: cloudflare(),
});
---
// src/pages/api/search.ts — s'exécute en périphérie
export const prerender = false;
export async function GET({ request }) {
const url = new URL(request.url);
const q = url.searchParams.get('q') ?? '';
const results = await search(q);
return new Response(JSON.stringify(results), { headers: { 'content-type': 'application/json' } });
}
prerender = false opte une route pour le SSR ; le reste du site reste statique.
Anti-patrons
client:load partout
Symptôme : Le bundle JS de Lighthouse gonfle ; l'histoire d'hydratation d'Astro disparaît.
Diagnostic : Les ingénieurs utilisent client:load par défaut car c'est le plus familier.
Correctif : Utilisez client:idle ou client:visible par défaut. Réservez client:load pour l'interactif visible sans défilement.
Récupération de données dans les composants client
Symptôme : Spinners de chargement sur chaque page ; SEO affecté.
Diagnostic : La récupération de données a été déplacée vers les composants React au lieu du frontmatter Astro.
Correctif : Récupérez dans les délimiteurs ---, rendez côté serveur, passez les données comme props aux îles.
Frontmatter non typé
Symptôme : La construction réussit ; la production affiche undefined dans les titres.
Diagnostic : Pas de schéma de collection de contenu ; une faute de frappe dans le frontmatter est passée inaperçue.
Correctif : Utilisez defineCollection avec un schéma zod. Les erreurs de frontmatter font échouer la construction.
Mélange de public/ et src/assets/ pour les images
Symptôme : Certaines images optimisées, d'autres livrées à leur taille d'origine.
Diagnostic : public/ est servi tel quel ; seul src/assets/ passe par Sharp.
Correctif : Déplacez les images vers src/assets/. Utilisez <Image> partout. public/ uniquement pour les images OG et les favicons.
Essayer d'utiliser Astro pour une SPA
Symptôme : Lutte constante avec l'hydratation ; les îles grandissent jusqu'à ce que toute la page soit interactive. Diagnostic : Mauvais framework pour le travail. Astro excelle pour le contenu ; les SPA ont besoin de Next/Remix. Correctif : Utilisez Next/Remix lorsque la plupart des pages sont interactives. Utilisez Astro pour le marketing et la documentation.
Utilisation excessive de client:only
Symptôme : Décalage de mise en page (CLS) à chaque chargement de page ; « clignotement » avant l'affichage du contenu.
Diagnostic : Ignorer le SSR signifie que le navigateur voit un espace réservé vide jusqu'à ce que le JS s'exécute.
Correctif : Utilisez client:only uniquement lorsque le composant ne peut vraiment pas être rendu côté serveur. Fournissez un espace réservé qui se rapproche de la taille finale.
Contrôles de qualité
- La directive client par défaut est
client:idleouclient:visible;client:loadjustifié par cas d'utilisation. - Tout le contenu a un schéma typé via
defineCollection. - Les images se trouvent sous
src/assets/et utilisent le composant<Image>. - Les intégrations multi-framework (
@astrojs/react, etc.) ajoutées uniquement pour les composants qui existent. - LCP inférieur à 2s sur la page représentative la plus lente.
- Budget JS de premier chargement défini par page ; la CI échoue en cas de régressions.
- MDX utilise des composants Astro pour les parties statiques ; îles uniquement là où c'est interactif.
- Transitions de vue testées sur les principaux chemins de navigation.
PAS pour
- SPA complètes — Next.js, Remix, TanStack Start sont plus adaptés.
- Écriture de plugins/intégrations Astro — compétence séparée (pas encore de compétence dédiée).
- Réglage de la construction côté Vite — Astro utilise Vite en interne. →
vite-build-optimizerpour le dimensionnement des chunks, le HMR, les problèmes de cycle de vie des plugins. - Applications à état client lourd (tableaux de bord, outils en temps réel) — trop de JS pour que les îles aident.
- Mobile natif — Astro est uniquement Web.