Skip to content

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

  • ✅ title est toujours obligatoire
  • ✅ pubDate est toujours obligatoire
  • ✅ heroImage est optionnel (affichage conditionnel)
  • ✅ updatedDate est 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 alt vide 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
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

Terminal window
# Test local
npm run dev
# Vérification de l'accessibilité
npx axe http://localhost:4321/
# Vérification des performances
npx lighthouse http://localhost:4321/

11.3. Logs et monitoring

Terminal window
# Logs de build
npm run build -- --verbose
# Vérification des types
npx astro check

12. 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

14. Ressources liées2/2

  • Composants utilisés :
    • src/components/BaseHead.astro
    • src/components/Header.astro
    • src/components/Footer.astro
    • src/components/FormattedDate.astro

15. Historique des modifications

Date Version Description Auteur
2026-09-15 1.0 Création initiale Devin
Switch to normal mode

Contents