BlogPost
BlogPost
Documentation technique
Type de ressource : Layout Astro (Gabarit de page)
Fichier source :src/layouts/BlogPost.astro
Statut : Actif
1. Vue d’overview
1.1. Description
Layout pour les articles de blog. Fournit la structure HTML complète pour les pages d’articles, incluant l’en-tête, l’image héro, la date de publication, la date de mise à jour, et le contenu de l’article.
1.2. Objectif
- Fournir une structure cohérente pour tous les articles de blog
- Afficher les métadonnées de l’article (titre, dates, image)
- Intégrer les composants globaux (Header, Footer)
- Optimiser le rendu des images via Astro Assets
1.3. Périmètre concerné
- Type de pages : Blog (articles individuels)
- Mode de rendu : SSG (via Astro content collections)
- Consommateurs :
src/pages/blog/[...slug].astro
2. Architecture et structure
2.1. Diagramme de flux
[Page Astro (blog/[...slug].astro)] │ (import du layout) ▼[BlogPost Layout] │ • Structure HTML complète │ • Injection des métadonnées SEO (via BaseHead) │ • Inclusion des composants globaux (Header, Footer) │ • Affichage de l'image héro │ • Affichage des dates (pubDate, updatedDate) │ • Gestion du slot de contenu ▼[HTML final]2.2. Composants impliqués
| Composant | Rôle | Fichier |
|---|---|---|
| BaseHead | Métadonnées SEO globales | src/components/BaseHead.astro |
| Header | Navigation globale | src/components/Header.astro |
| Footer | Pied de page global | src/components/Footer.astro |
| FormattedDate | Formatage des dates | src/components/FormattedDate.astro |
| Slot de contenu | Zone de contenu dynamique | <slot /> |
3. Implémentation
3.1. Code du layout1/2
3.1. Code du layout2/2
---import { Image } from 'astro:assets';import type { CollectionEntry } from 'astro:content';import BaseHead from '../components/BaseHead.astro';import Footer from '../components/Footer.astro';import FormattedDate from '../components/FormattedDate.astro';import Header from '../components/Header.astro';
type Props = CollectionEntry<'blog'>['data'];
const { title, description, pubDate, updatedDate, heroImage } = Astro.props;---
<html lang="en"> <head> <BaseHead title={title} description={description} /> <style> main { width: calc(100% - 2em); max-width: 100%; margin: 0; } .hero-image { width: 100%; } .hero-image img { display: block; margin: 0 auto; border-radius: 12px; box-shadow: var(--box-shadow); } .prose { width: 720px; max-width: calc(100% - 2em); margin: auto; padding: 1em; color: rgb(var(--gray-dark)); } .title { margin-bottom: 1em; padding: 1em 0; text-align: center; line-height: 1; } .title h1 { margin: 0 0 0.5em 0; } .date { margin-bottom: 0.5em; color: rgb(var(--gray)); } .last-updated-on { font-style: italic; } </style> </head>
<body> <Header /> <main> <article> <div class="hero-image"> {heroImage && <Image width={1020} height={510} src={heroImage} alt="" />} </div> <div class="prose"> <div class="title"> <div class="date"> <FormattedDate date={pubDate} /> { updatedDate && ( <div class="last-updated-on"> Last updated on <FormattedDate date={updatedDate} /> </div> ) } </div> <h1>{title}</h1> <hr /> </div> <slot /> </div> </article> </main> <Footer /> </body></html>3.2. Utilisation dans une page
---import BlogPost from '../../layouts/BlogPost.astro';import { getCollection } from 'astro:content';
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();---
<BlogPost {...post.data}> <Content /></BlogPost>4. Props et interface
4.1. Props obligatoires
| Prop | Type | Description | Exemple |
|---|---|---|---|
title |
string |
Titre de l’article | "Mon article de blog" |
pubDate |
Date |
Date de publication | new Date('2024-01-15') |
4.2. Props optionnelles
| Prop | Type | Description | Valeur par défaut |
|---|---|---|---|
description |
string |
Meta description | undefined |
updatedDate |
Date |
Date de mise à jour | undefined |
heroImage |
ImageMetadata |
Image héro de l’article | undefined |
4.3. Slots
| Slot | Description | Obligatoire |
|---|---|---|
default |
Contenu principal de l’article | ✅ |
5. SEO et métadonnées
5.1. Balises meta injectées
| Balise | Source | Fallback |
|---|---|---|
<title> |
props.title |
- |
<meta name="description"> |
props.description |
- |
| Meta tags globaux | BaseHead |
- |
5.2. Structured Data (JSON-LD)
Non implémenté - ce layout n’injecte pas de JSON-LD.
5.3. Règles de fallback
- ✅
titleest toujours obligatoire - ✅
pubDateest toujours obligatoire - ✅
heroImageest optionnel (affichage conditionnel) - ✅
updatedDateest optionnel (affichage conditionnel)
6. Accessibilité (a11y)
6.1. Structure sémantique
<body> <Header />
<main> <article> <div class="hero-image"> <Image /> </div> <div class="prose"> <div class="title"> <time> <FormattedDate /> </time> <h1>{title}</h1> </div> <slot /> </div> </article> </main>
<Footer /></body>6.2. Règles d’accessibilité
- ✅ Structure HTML sémantique (
<header>,<main>,<article>,<footer>) - ✅ Attribut
lang="en"sur<html> - ⚠️ Pas de skip link vers le contenu principal
- ⚠️ Attribut
altvide pour l’image héro (à corriger) - ⚠️ Focus visible non testé
- ⚠️ Contraste WCAG AA non testé
7. Styles et design system
7.1. Utilisation des design tokens
/* Le layout utilise des variables CSS personnalisées */.prose { color: rgb(var(--gray-dark));}
.hero-image img { box-shadow: var(--box-shadow);}7.2. Responsive design
/* Responsive par défaut */main { width: calc(100% - 2em); max-width: 100%;}
.prose { width: 720px; max-width: calc(100% - 2em);}7.3. Mode sombre
Non implémenté - le layout utilise les couleurs par défaut.
8. Composants globaux inclus
8.1. Header
| Composant | Rôle | Hydratation |
|---|---|---|
Header.astro |
Navigation globale, logo, menu | Aucune |
8.2. Footer
| Composant | Rôle | Hydratation |
|---|---|---|
Footer.astro |
Liens, copyright, réseaux sociaux | Aucune |
8.3. Autres composants globaux
| Composant | Rôle | Hydratation |
|---|---|---|
BaseHead.astro |
Métadonnées SEO globales | Aucune |
FormattedDate.astro |
Formatage des dates | Aucune |
9. Intégration avec les pages
9.1. Utilisation dans une page SSG
---import BlogPost from '../../layouts/BlogPost.astro';import { getCollection } from 'astro:content';
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();---
<BlogPost {...post.data}> <Content /></BlogPost>9.2. Pages utilisant ce layout
| Page | Fichier | Mode |
|---|---|---|
| Blog post | src/pages/blog/[...slug].astro |
SSG |
10. Performance et optimisation
10.1. Optimisations appliquées
- ✅ HTML statique par défaut (pas de JavaScript)
- ✅ Images optimisées via Astro Assets (width, height spécifiés)
- ✅ CSS scoped minimal
- ✅ Pas de JavaScript bloquant
10.2. Core Web Vitals
| Métrique | Objectif | Stratégie |
|---|---|---|
| LCP | < 2.5s | Images optimisées via Astro Assets |
| INP | < 200ms | Pas de JavaScript |
| CLS | < 0.1 | Dimensions explicites des images |
10.3. Cache
| Type | Cache-Control | Rationale |
|---|---|---|
| HTML (SSG) | public, max-age=31536000, immutable |
Contenu statique |
| CSS/JS | public, max-age=31536000, immutable |
Assets versionnés |
11. Débogage et troubleshooting
11.1. Problèmes courants
| Symptôme | Cause probable | Solution |
|---|---|---|
| Layout non appliqué | Import incorrect | Vérifier le chemin d’import |
| Image non affichée | heroImage manquant | Vérifier que l’image est dans la collection |
| Dates incorrectes | Format de date invalide | Vérifier que les dates sont des objets Date valides |
| Styles cassés | Variables CSS non définies | Vérifier les variables CSS personnalisées |
11.2. Tests manuels
# Test localnpm run dev
# Vérification de l'accessibiliténpx axe http://localhost:4321/
# Vérification des performancesnpx lighthouse http://localhost:4321/11.3. Logs et monitoring
# Logs de buildnpm run build -- --verbose
# Vérification des typesnpx astro check12. Bonnes pratiques
12.1. Architecture
- ✅ Centraliser la structure HTML dans le layout
- ✅ Utiliser Astro Assets pour l’optimisation des images
- ✅ Utiliser les composants globaux (Header, Footer)
- ✅ Séparer le CSS scoped du CSS global
12.2. Code
- ✅ Typer les props avec TypeScript
- ✅ Utiliser des valeurs par défaut pour les props optionnelles
- ✅ Affichage conditionnel pour les éléments optionnels (heroImage, updatedDate)
12.3. Maintenance
- ✅ Mettre à jour les styles si nécessaire
- ✅ Tester l’accessibilité régulièrement
- ⚠️ Ajouter un skip link pour l’accessibilité
- ⚠️ Corriger l’attribut alt vide pour l’image héro
13. Évolutions et roadmap
13.1. Améliorations planifiées
- Ajout d’un skip link pour l’accessibilité
- Correction de l’attribut alt pour l’image héro
- Ajout du structured data (JSON-LD) pour les articles
- Support du mode sombre
- Ajout d’un breadcrumbs automatique
13.2. Limitations connues
- ❌ Pas de skip link
- ❌ Attribut alt vide pour l’image héro
- ❌ Pas de structured data (JSON-LD)
- ❌ Pas de mode sombre
- ❌ Locale hardcodée (‘en’)
14. Ressources liées1/2
- Documentation Astro : Layouts
- Documentation Astro : Astro Assets
- Documentation Astro : Content Collections
- Layouts associés : Aucun (layout indépendant)
14. Ressources liées2/2
- Composants utilisés :
src/components/BaseHead.astrosrc/components/Header.astrosrc/components/Footer.astrosrc/components/FormattedDate.astro
15. Historique des modifications
| Date | Version | Description | Auteur |
|---|---|---|---|
| 2026-09-15 | 1.0 | Création initiale | Devin |