Définir les métadonnées de chaque itinéraire
Objectif : Générer un titre et une description uniques à partir des données de chaque itinéraire.
Un titre identique sur toutes les pages du catalogue ne décrit pas correctement l’itinéraire consulté. Les moteurs de recherche et les visiteurs doivent pouvoir distinguer, dès le résultat de recherche, la page des Crêtes du Jura d’une autre randonnée.
Vous allez relier les métadonnées de la route dynamique à la même source de données que son contenu. Next.js générera alors un titre et une description adaptés au slug demandé, sans ajouter de code exécuté dans le navigateur.
Distinguer métadonnées statiques et générées
L’API Metadata de Next.js permet de déclarer les informations d’une page à partir de ses modules serveur. Une page dont le titre ne dépend pas de ses données peut exporter un objet metadata statique. Pour une route comme /randonnees/[slug], le titre et la description varient selon l’itinéraire : vous exportez donc une fonction generateMetadata. Next.js l’appelle pour la route demandée et intègre ses valeurs aux balises <title> et <meta name="description">.
La fonction et le rendu de la page doivent s’appuyer sur la même fonction d’accès aux données. Cela évite de fabriquer un titre pour un itinéraire différent de celui affiché. Dans cet exemple, le catalogue contient les Crêtes du Jura ; le type et la fonction de recherche restent simples et peuvent être étendus avec les autres itinéraires du projet.
Définir les données et le générateur
Ajoutez les données nécessaires à la route dans lib/randonnees.ts. Le slug est l’identifiant de l’URL ; le nom et le résumé servent à produire à la fois le contenu visible et les métadonnées. La fonction renvoie undefined lorsque le slug est inconnu, ce qui permet à la page de répondre avec une page 404 plutôt que des métadonnées inventées.
export type Randonnee = {
slug: string
nom: string
resume: string
description: string
image: string
texteAlt: string
}
const randonnees: Randonnee[] = [
{
slug: "cretes-du-jura",
nom: "Crêtes du Jura",
resume: "Parcourez les crêtes du Jura et profitez des panoramas du massif.",
description: "Un itinéraire de randonnée sur les crêtes du Jura, entre paysages ouverts et reliefs du massif.",
image: "/images/randonnees/cretes-du-jura.webp",
texteAlt: "Vue des crêtes du Jura"
}
]
export function obtenirRandonnee(slug: string): Randonnee | undefined {
return randonnees.find((randonnee) => randonnee.slug === slug)
}Centralisez ensuite la création des métadonnées dans lib/metadonnees.ts. Le type Metadata vérifie que l’objet respecte l’API de Next.js. Le préfixe descriptif du titre reste constant, tandis que le nom et le résumé viennent des données propres à chaque randonnée.
import type { Metadata } from "next"
import type { Randonnee } from "./randonnees"
export function creerMetadonneesRandonnee(randonnee: Randonnee): Metadata {
return {
title: `${randonnee.nom} | Randonnées`,
description: randonnee.resume
}
}Relier les métadonnées à la route dynamique
Remplacez le contenu de app/randonnees/[slug]/page.tsx par le module complet ci-dessous. Dans les versions récentes de Next.js, les paramètres d’une route dynamique sont asynchrones : le code attend params avant d’extraire le slug. La page et generateMetadata appellent ensuite la même fonction d’accès aux données.
import type { Metadata } from "next"
import { notFound } from "next/navigation"
import { creerMetadonneesRandonnee } from "@/lib/metadonnees"
import { obtenirRandonnee } from "@/lib/randonnees"
type Props = {
params: Promise<{ slug: string }>
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const randonnee = obtenirRandonnee(slug)
if (!randonnee) {
notFound()
}
return creerMetadonneesRandonnee(randonnee)
}
export default async function PageRandonnee({ params }: Props) {
const { slug } = await params
const randonnee = obtenirRandonnee(slug)
if (!randonnee) {
notFound()
}
return (
<article className="rando-detail" aria-labelledby="titre-itineraire">
<h1 id="titre-itineraire">{randonnee.nom}</h1>
<div className="rando-detail__media">
<img src={randonnee.image} alt={randonnee.texteAlt} />
</div>
<p>{randonnee.description}</p>
</article>
)
}La page produit le contenu HTML de l’itinéraire ; les valeurs visibles restent échappées par React. Pour /randonnees/cretes-du-jura, le résultat attendu dans le document rendu est un titre de page « Crêtes du Jura | Randonnées » et une description correspondant au résumé défini dans les données. Pour un slug inconnu, notFound() interrompt le rendu normal et déclenche la réponse 404 de Next.js.
Vérifier le résultat
Lancez le serveur selon les scripts de votre projet, puis consultez la route de l’itinéraire. Dans le navigateur, utilisez l’inspection du document ou affichez la source reçue par le serveur : vérifiez les valeurs de <title> et de la balise de description. Testez également un slug inexistant pour confirmer qu’il ne reçoit pas les métadonnées des Crêtes du Jura. Répétez ces vérifications sur chaque route ajoutée ; le rapport Lighthouse de référence et le budget JavaScript restent vos contrôles de non-régression, comme défini dans les leçons précédentes.
À retenir
- Une route dynamique utilise `generateMetadata` lorsque ses métadonnées dépendent de ses données.
- Faites partager à la page et au générateur de métadonnées la même fonction de recherche par slug.
- Construisez un titre lisible et une description utile à partir des champs de l’itinéraire.
- Traitez les slugs inconnus avec `notFound()` et vérifiez les balises produites pour chaque route.
Dans la prochaine leçon, vous compléterez ces métadonnées avec les informations nécessaires aux aperçus de partage.