Un blog culinaire à forte fréquentation, plus de six cents recettes publiées, a besoin d’exactement une fonctionnalité interactive : une recherche en direct qui filtre les recettes pendant que le visiteur tape, sans recharger la page. Tout le reste, du menu à l’affichage d’une recette complète, reste du contenu purement statique, sans le moindre besoin de JavaScript. C’est exactement le scénario pour lequel Astro et son architecture en îles (Islands) ont été pensés, et ce cas concret le démontre sur un projet réel livré ce printemps.
Cet article ne traite pas d’Astro et de son Content Layer, une fonctionnalité plus récente couverte dans un article ultérieur de ce blog. Il se concentre sur l’usage le plus simple et le plus caractéristique d’Astro : une île isolée dans un océan de pages statiques.
Le principe des Islands, appliqué à ce projet
Par défaut, une page .astro ne charge aucun JavaScript côté client, même si elle contient des composants React ou Vue importés dans son code. Seuls les composants explicitement marqués avec une directive client:* reçoivent leur propre bundle JavaScript, hydraté indépendamment du reste de la page. Sur ce blog, seule la barre de recherche a reçu cette directive, tout le reste du gabarit de page reste du HTML pur généré au build.
La page de listing, entièrement statique
---
// src/pages/recettes/index.astro
import { getCollection } from 'astro:content'
import BarreRecherche from '../../components/BarreRecherche.jsx'
const reponse = await fetch(
'https://api.exemple.fr/wp-json/wp/v2/recette?per_page=100&_fields=id,slug,title,acf'
)
const recettes = await reponse.json()
---
<html lang="fr">
<body>
<h1>Toutes nos recettes</h1>
<BarreRecherche client:load recettes={recettes} />
<ul>
{recettes.map((recette) => (
<li>
<a href={`/recettes/${recette.slug}`}>{recette.title.rendered}</a>
</li>
))}
</ul>
</body>
</html>
La liste complète des recettes est générée directement dans le HTML statique, sans passer par l’île de recherche : celle-ci ne fait que filtrer visuellement cette même liste une fois hydratée côté client, elle n’est jamais responsable du rendu initial.

L’île de recherche, seule partie réellement interactive
// src/components/BarreRecherche.jsx
import { useState } from 'react'
export default function BarreRecherche({ recettes }) {
const [filtre, setFiltre] = useState('')
const recettesFiltrees = recettes.filter((r) =>
r.title.rendered.toLowerCase().includes(filtre.toLowerCase())
)
return (
<div>
<input
type="search"
placeholder="Chercher une recette"
value={filtre}
onChange={(e) => setFiltre(e.target.value)}
/>
{filtre && (
<ul>
{recettesFiltrees.map((r) => (
<li key={r.id}>
<a href={`/recettes/${r.slug}`}>{r.title.rendered}</a>
</li>
))}
</ul>
)}
</div>
)
}
La directive client:load indique à Astro d’hydrater ce composant dès le chargement de la page, un choix justifié ici puisque la barre de recherche doit être immédiatement utilisable. Sur une île moins prioritaire, client:visible aurait retardé l’hydratation jusqu’à ce que le composant entre dans le champ de vision du visiteur, pour économiser encore un peu de temps de chargement initial.
Le résultat mesuré
| Métrique | Avant (thème classique) | Après (Astro Islands) |
|---|---|---|
| JavaScript total chargé | 187 Ko | 14 Ko |
| Temps d’interactivité (TTI) | 2,4 s | 0,6 s |
| Score Lighthouse Performance | 71 | 98 |
Pourquoi ce choix n’aurait pas fonctionné pour un site plus interactif
- Un site avec un espace membre, un panier ou une messagerie interne aurait vu ses îles se multiplier au point de perdre l’intérêt de l’approche, chaque île ajoutant un point d’hydratation à coordonner.
- Le partage d’état entre plusieurs îles distinctes reste plus artisanal qu’avec une application React unifiée, un compromis acceptable ici puisqu’une seule île existe sur tout le site.
- Astro reste avant tout pensé pour du contenu majoritairement statique : un site fortement applicatif gagnerait probablement plus à choisir un framework pensé pour ça dès le départ.
Le bon réflexe avec Astro n’est pas de se demander « comment rendre ma page interactive », mais « quelle est la plus petite partie de ma page qui a réellement besoin de l’être ».
En résumé
Sur ce blog culinaire, une seule île Astro suffit à couvrir l’unique besoin d’interactivité réel du site, laissant tout le reste du contenu strictement statique et donc extrêmement rapide à charger. Le gain de performance mesuré n’a rien d’anecdotique : il illustre exactement la promesse d’Astro, livrer du JavaScript uniquement là où il apporte une vraie valeur, jamais par défaut sur l’ensemble d’un site.