Framework Web Astro
Vue d'ensemble
Astro est un framework web conçu pour les sites riches en contenu — blogs, documentation, portfolios, sites marketing et e-commerce. Son innovation principale est l'architecture en îlots : par défaut, Astro n'envoie aucun JavaScript au navigateur. Les composants interactifs sont hydratés de manière sélective sous forme d'« îlots » isolés. Astro prend en charge les frameworks React, Vue, Svelte, Solid et d'autres simultanément dans le même projet, vous permettant de choisir l'outil adapté pour chaque composant.
Quand utiliser cette compétence
- À utiliser lors de la création d'un blog, d'un site de documentation, d'une page marketing ou d'un portfolio
- À utiliser lorsque la performance et les Core Web Vitals sont la priorité absolue
- À utiliser lorsque le projet est riche en contenu avec des fichiers Markdown ou MDX
- À utiliser lorsque vous souhaitez une sortie SSG (statique) avec un SSR optionnel pour les routes dynamiques
- À utiliser lorsque l'utilisateur pose des questions sur les fichiers
.astro,Astro.props, les collections de contenu ou les directivesclient:
Comment ça fonctionne
Étape 1 : Configuration du projet
npm create astro@latest my-site
cd my-site
npm install
npm run dev
Ajoutez des intégrations selon les besoins :
npx astro add tailwind # Tailwind CSS
npx astro add react # Support des composants React
npx astro add mdx # Support MDX
npx astro add sitemap # sitemap.xml automatique
npx astro add vercel # Adaptateur SSR Vercel
Structure du projet :
src/
pages/ ← Routage basé sur les fichiers (.astro, .md, .mdx)
layouts/ ← Coques de pages réutilisables
components/ ← Composants d'interface (.astro, .tsx, .vue, etc.)
content/ ← Collections de contenu typées (Markdown/MDX)
styles/ ← CSS global
public/ ← Actifs statiques (copiés tels quels)
astro.config.mjs ← Configuration du framework
Étape 2 : Syntaxe des composants Astro
Les fichiers .astro ont une barrière de code en haut (serveur uniquement) et un modèle en dessous :
---
// src/components/Card.astro
// Ce bloc s'exécute UNIQUEMENT sur le serveur — jamais dans le navigateur
interface Props {
title: string;
href: string;
description: string;
}
const { title, href, description } = Astro.props;
---
<article class="card">
<h2><a href={href}>{title}</a></h2>
<p>{description}</p>
</article>
<style>
/* Scopé automatiquement à ce composant */
.card { border: 1px solid #eee; padding: 1rem; }
</style>
Étape 3 : Pages basées sur les fichiers et routage
src/pages/index.astro → /
src/pages/about.astro → /about
src/pages/blog/[slug].astro → /blog/:slug (dynamique)
src/pages/blog/[...path].astro → /blog/* (tout capturer)
Route dynamique avec getStaticPaths :
---
// src/pages/blog/[slug].astro
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<h1>{post.data.title}</h1>
<Content />
Étape 4 : Collections de contenu
Les collections de contenu vous donnent un accès typé aux fichiers Markdown et MDX :
// src/content/config.ts
import { z, defineCollection } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };
---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
const posts = (await getCollection('blog'))
.filter(p => !p.data.draft)
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
---
<ul>
{posts.map(post => (
<li>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
<time>{post.data.date.toLocaleDateString()}</time>
</li>
))}
</ul>
Étape 5 : Îlots — Hydratation sélective
Par défaut, les composants du framework UI sont rendus en HTML statique sans JS. Utilisez les directives client: pour hydrater :
---
import Counter from '../components/Counter.tsx'; // Composant React
import VideoPlayer from '../components/VideoPlayer.svelte';
---
<!-- HTML statique — aucun JavaScript envoyé au navigateur -->
<Counter initialCount={0} />
<!-- Hydrater immédiatement au chargement de la page -->
<Counter initialCount={0} client:load />
<!-- Hydrater lorsque le composant défile dans la vue -->
<VideoPlayer src="/demo.mp4" client:visible />
<!-- Hydrater uniquement lorsque le navigateur est inactif -->
<Analytics client:idle />
<!-- Hydrater uniquement sur une requête média spécifique -->
<MobileMenu client:media="(max-width: 768px)" />
Étape 6 : Layouts
---
// src/layouts/BaseLayout.astro
interface Props {
title: string;
description?: string;
}
const { title, description = 'Mon site Astro' } = Astro.props;
---
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>{title}</title>
<meta name="description" content={description} />
</head>
<body>
<nav>...</nav>
<main>
<slot /> <!-- le contenu de la page s'affiche ici -->
</main>
<footer>...</footer>
</body>
</html>
---
// src/pages/about.astro
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="À propos">
<h1>À propos</h1>
<p>Bienvenue sur notre entreprise...</p>
</BaseLayout>
Étape 7 : Mode SSR (Rendu à la demande)
Activez le SSR pour les pages dynamiques en définissant un adaptateur :
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'hybrid', // 'static' | 'server' | 'hybrid'
adapter: vercel(),
});
Optez pour des pages individuelles en SSR avec export const prerender = false.
Exemples
Exemple 1 : Blog avec flux RSS
// src/pages/rss.xml.ts
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
export async function GET(context) {
const posts = await getCollection('blog');
return rss({
title: 'Mon blog',
description: 'Derniers articles',
site: context.site,
items: posts.map(post => ({
title: post.data.title,
pubDate: post.data.date,
link: `/blog/${post.slug}/`,
})),
});
}
Exemple 2 : Point de terminaison API (SSR)
// src/pages/api/subscribe.ts
import type { APIRoute } from 'astro';
export const POST: APIRoute = async ({ request }) => {
const { email } = await request.json();
if (!email) {
return new Response(JSON.stringify({ error: 'Email requis' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
await addToNewsletter(email);
return new Response(JSON.stringify({ success: true }), { status: 200 });
};
Exemple 3 : Composant React en tant qu'îlot
// src/components/SearchBox.tsx
import { useState } from 'react';
export default function SearchBox() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
async function search(e: React.FormEvent) {
e.preventDefault();
const data = await fetch(`/api/search?q=${query}`).then(r => r.json());
setResults(data);
}
return (
<form onSubmit={search}>
<input value={query} onChange={e => setQuery(e.target.value)} />
<button type="submit">Rechercher</button>
<ul>{results.map(r => <li key={r.id}>{r.title}</li>)}</ul>
</form>
);
}
---
import SearchBox from '../components/SearchBox.tsx';
---
<!-- Hydraté immédiatement — cet îlot est interactif -->
<SearchBox client:load />
Meilleures pratiques
- ✅ Conservez la plupart des composants sous forme de fichiers
.astrostatiques — n'hydratez que ce qui doit être interactif - ✅ Utilisez les collections de contenu pour tout le contenu Markdown/MDX — vous bénéficiez de la sécurité de type et de la validation automatique
- ✅ Préférez
client:visibleàclient:loadpour les composants situés sous la ligne de flottaison afin de réduire le JS initial - ✅ Utilisez
import.meta.envpour les variables d'environnement — préfixez les variables publiques avecPUBLIC_ - ✅ Ajoutez
<ViewTransitions />depuisastro:transitionspour une navigation fluide entre les pages sans SPA complet - ❌ N'utilisez pas
client:loadsur tous les composants — cela annule l'avantage de performance d'Astro - ❌ Ne mettez pas de secrets dans le frontmatter
.astroutilisé dans les modèles côté client - ❌ N'omettez pas
getStaticPathspour les routes dynamiques en mode statique — les builds échoueront
Remarques sur la sécurité
- Le code du frontmatter dans les fichiers
.astros'exécute uniquement côté serveur et n'est jamais exposé au navigateur. - Utilisez
import.meta.env.PUBLIC_*uniquement pour les valeurs non sensibles. Les variables d'environnement privées (sans préfixePUBLIC_) ne sont jamais envoyées au client. - Lors de l'utilisation du mode SSR, validez toutes les entrées
Astro.requestavant les requêtes de base de données ou les appels API. - Assainissez tout contenu fourni par l'utilisateur avant de le rendere avec
set:html— cela contourne l'échappement automatique.
Pièges courants
-
Problème : Le JavaScript d'un composant React/Vue ne s'exécute pas dans le navigateur Solution : Ajoutez une directive
client:(client:load,client:visible, etc.) — sans elle, les composants sont rendus en HTML statique uniquement. -
Problème : Les données
getStaticPathssont obsolètes après les mises à jour de contenu pendant le développement Solution : Le serveur de développement d'Astro surveille les fichiers de contenu — redémarrez si les modifications apportées àcontent/config.tsne sont pas reflétées. -
Problème : Le type
Astro.propsestany— pas d'autocomplétion Solution : Définissez une interface ou un typePropsdans le frontmatter et Astro l'inférera automatiquement. -
Problème : Le CSS d'un composant
.astrose répand dans d'autres composants Solution : Les styles dans les balises<style>de.astrosont automatiquement scopés. Utilisez:global()uniquement lorsque vous ciblez intentionnellement les enfants.
Compétences connexes
@sveltekit— Lorsque vous avez besoin d'un framework full-stack avec une UI réactive (vs l'approche contenu d'Astro)@nextjs-app-router-patterns— Lorsque vous avez besoin d'un framework full-stack axé sur React@tailwind-patterns— Styliser les sites Astro avec Tailwind CSS@progressive-web-app— Ajouter des capacités PWA à un site Astro
Limitations
- Utilisez cette compétence uniquement lorsque la tâche correspond clairement au périmètre décrit ci-dessus.
- Ne considérez pas la sortie comme un substitut à une validation spécifique à l'environnement, des tests ou une revue par un expert.
- Arrêtez-vous et demandez des clarifications si les entrées requises, les autorisations, les limites de sécurité ou les critères de succès sont manquants.