Leçon 4 / 15

Définir les métadonnées de chaque itinéraire

20 min Next.js — performance, SEO et mise en production Gratuit

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.

lib/randonnees.tsTypeScript
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.

lib/metadonnees.tsTypeScript
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.

app/randonnees/[slug]/page.tsxTexte
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.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.