Frameworks

Astro : le framework pour des sites statiques ultra-rapides

Mark Toledo

Mark Toledo

1 avril 2026

Astro : le framework pour des sites statiques ultra-rapides

Il y a deux ans, j'avais un client qui voulait refaire son site vitrine. Le site existant était un WordPress avec trop de plugins, un Time To First Byte de 3 secondes, et un score Lighthouse autour de 45. On avait essayé Nuxt et Next.js en mode SSG, mais même là, le bundle JavaScript envoyé au client était trop lourd pour un site qui n'avait besoin que d'afficher du contenu et d'un formulaire de contact.

C'est là qu'on a testé Astro. Le résultat : score Lighthouse 98, TTFB sous 200ms, et zero JavaScript envoyé sur les pages statiques. Depuis, c'est mon choix par défaut pour ce type de projet.

L'idée derrière Astro

Astro part d'une philosophie simple : la plupart des sites web n'ont pas besoin de JavaScript côté client. Un blog, un portfolio, une documentation, une page marketing — tout ça peut être du HTML pur, servi depuis un CDN.

Le concept central s'appelle "Zero JS by default". Astro génère du HTML statique et n'envoie du JavaScript au navigateur que quand tu le demandes explicitement. C'est l'inverse de la plupart des frameworks React ou Vue, où tout est JavaScript et tu dois explicitement désactiver ce que tu ne veux pas.

La structure d'un projet Astro

npm create astro@latest mon-site
cd mon-site
npm install
npm run dev

La structure générée est claire :

src/
  components/    # Composants Astro et UI
  layouts/       # Layouts de page
  pages/         # Chaque fichier = une route
  content/       # Collections de contenu (blog, docs...)
public/          # Assets statiques
astro.config.mjs

Les composants Astro

La syntaxe des composants .astro ressemble à du HTML avec une section script frontmatter. Ce qui s'exécute dans le frontmatter s'exécute côté serveur au moment du build — pas dans le navigateur.

---
// Ce code s'exécute au build, pas dans le navigateur
const { titre, auteur } = Astro.props;
const dateFormatee = new Date().toLocaleDateString('fr-FR');
---

<article>
  <h1>{titre}</h1>
  <p>Par {auteur} — {dateFormatee}</p>
  <slot />
</article>

Rien de ce code JavaScript ne finit dans le bundle client. Le HTML généré est pur, sans trace du framework.

L'architecture des îles

C'est le concept qui rend Astro vraiment différent. L'idée : la plupart d'une page est statique, mais certaines parties ont besoin d'interactivité. Ces parties s'appellent des "îles" — des composants interactifs isolés dans un océan de HTML statique.

---
import MonComposantVue from './MonComposant.vue';
import CompteurReact from './Compteur.jsx';
---

<!-- HTML statique — aucun JS -->
<header>
  <h1>Mon Site</h1>
</header>

<!-- Île Vue — hydratée uniquement quand visible -->
<MonComposantVue client:visible />

<!-- Île React — hydratée dès le chargement -->
<CompteurReact client:load />

Les directives client:* contrôlent quand l'hydratation se produit :

  • client:load : dès que possible
  • client:idle : quand le navigateur est inactif
  • client:visible : quand l'élément entre dans le viewport
  • client:only : uniquement côté client, jamais rendu en SSR

Intégration multi-frameworks

Une des forces d'Astro : tu peux mixer React, Vue, Svelte et SolidJS dans le même projet. Chaque composant est une île indépendante.

npx astro add react vue svelte
---
import FormulaireReact from './Formulaire.jsx';
import GraphiqueVue from './Graphique.vue';
import AnimationSvelte from './Animation.svelte';
---

<main>
  <FormulaireReact client:load />
  <GraphiqueVue client:visible />
  <AnimationSvelte client:idle />
</main>

En pratique, je conseille de choisir un seul framework UI et de s'y tenir. Mixer trois frameworks dans un seul projet, c'est techniquement possible mais ça complexifie la maintenance.

Les collections de contenu

Pour les blogs et la documentation, Astro propose un système de collections avec validation de schéma via Zod.

// src/content/config.ts
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    date: z.date(),
    author: z.string(),
    tags: z.array(z.string()).optional(),
    draft: z.boolean().default(false),
  })
});

export const collections = { blog };

La validation se fait au build. Si un fichier markdown a un frontmatter invalide, le build échoue avec un message d'erreur clair. C'est infiniment mieux que de découvrir des données manquantes en production.

---
import { getCollection } from 'astro:content';

const articles = await getCollection('blog', ({ data }) => {
  return !data.draft; // Filtrer les brouillons
});

articles.sort((a, b) => b.data.date - a.data.date);
---

<ul>
  {articles.map(article => (
    <li>
      <a href={`/blog/${article.slug}/`}>{article.data.title}</a>
    </li>
  ))}
</ul>

Routing et pages dynamiques

Comme Next.js, Astro utilise le système de fichiers pour le routing. Les routes dynamiques utilisent des crochets.

---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';

export async function getStaticPaths() {
  const articles = await getCollection('blog');
  return articles.map(article => ({
    params: { slug: article.slug },
    props: { article }
  }));
}

const { article } = Astro.props;
const { Content } = await article.render();
---

<article>
  <h1>{article.data.title}</h1>
  <Content />
</article>

Intégrations et plugins

L'écosystème Astro propose des intégrations officielles pour les cas courants :

npx astro add tailwind    # Tailwind CSS
npx astro add mdx         # MDX (Markdown + composants)
npx astro add sitemap     # Génération automatique sitemap
npx astro add image       # Optimisation d'images

L'intégration image est particulièrement utile — elle convertit automatiquement en WebP/AVIF et génère les attributs width et height pour éviter le layout shift.

---
import { Image } from 'astro:assets';
import monImage from '../assets/photo.jpg';
---

<Image
  src={monImage}
  alt="Description"
  width={800}
  format="webp"
/>

Déploiement

Astro génère par défaut un dossier dist/ de fichiers statiques, déployable sur n'importe quel hébergeur : Cloudflare Pages, Netlify, Vercel, ou même un simple bucket S3.

npm run build
# dist/ est prêt à être déployé

Pour des fonctionnalités dynamiques (SSR, API routes), il faut ajouter un adaptateur selon l'hébergeur cible :

npx astro add cloudflare  # Pour Cloudflare Workers
npx astro add node        # Pour un serveur Node.js

Comparaison avec Next.js et Nuxt

Astro n'est pas un remplacement universel pour Next.js ou Nuxt. Voici comment je choisis :

Astro quand le site est principalement statique : blog, documentation, portfolio, landing page. Le moins de JavaScript côté client, meilleures performances.

Next.js ou Nuxt quand l'application a beaucoup d'interactivité, de données dynamiques en temps réel, ou une authentification complexe. La richesse de l'écosystème React ou Vue justifie le poids supplémentaire.

La distinction devient floue avec les Server Components de React et les nouvelles fonctionnalités SSR d'Astro. Mais pour un site où le contenu est roi, Astro reste imbattable en termes de performance out-of-the-box.

Ce qu'on retient

Astro est un outil qui fait une chose très bien : générer des sites statiques rapides avec une excellente expérience développeur. Son architecture îles est une idée brillante qui permet d'ajouter de l'interactivité chirurgicalement, sans payer le coût d'un framework complet.

Si ton prochain projet est un site de contenu, un blog technique, ou une documentation, donne une chance à Astro. Le score Lighthouse de 98 que j'ai obtenu pour ce client n'était pas une optimisation — c'était le résultat par défaut.