Ajout page détail produit avec SEO sur React Router 7
Crée une fiche produit avec Markdown, meta SEO, JSON-LD et breadcrumb sous React Router 7. Améliore l’indexation et l’UX de ton appli.
Objectif de la leçon
Nous transformons la liste de robots humanoïdes en véritables fiches produit :
- migration Prisma pour ajouter
content(Markdown) au modèleProduct; - seed refactorisé avec des robots plus fun ;
- route dynamique
/products/:slug; - affichage SEO : balises meta + JSON-LD
Productet breadcrumb; - rendu Markdown SSR avec Tailwind Typography.
Tu suis ? On code ! 🚀
1 Migration : champ content dans Product
1model Product {2id String @id @default(uuid())3name String4slug String @unique5description String?6content String? // ^? contenu Markdown pour le SEO7priceCents Int8stock Int @default(0)9isActive Boolean @default(true)10/* … */11}
1npx prisma migrate dev --name add-product-content
Explication : le champ content stocke un texte Markdown riche (titres, tableaux, listes).
Le SEO adore : un seul H1 (le name), et le reste en H2/H3.
2 Nouveau seed plein d’humour
1/* … */2await prisma.product.create({3data: {4name: "Chef Gordon 2",5slug: "chef-gordon-2",6description: "Le robot cuistot étoilé !",7content: md`8### Fonctionnalités principales9| Tâche | Temps moyen |10| ----- | ----------- |11| Émincer un oignon | 2 s |12| Nettoyer le plan de travail | 5 s |1314> *Parce que « C’est trop cuit ! » n’existe plus.*15`,16priceCents: 799000,17stock: 12,18},19});
1npx prisma db seed
Pourquoi ? • descriptions longues → longue traîne SEO ; • Markdown = mise en page simple côté rédacteur.
3 Route dynamique products.$productSlug.tsx
Loader serveur
1import { getProduct } from "~/server/products.server";23export async function loader({ params }) {4const { product, productImages } = await getProduct({5productSlug: params.productSlug,6});7if (!product)8throw new Response("Produit introuvable", { status: 404 });9return { product, productImages };10}
Rappel : getProduct renvoie { product, productImages }
– si aucune image en base, on génère trois placeholders Picsum.
Balises meta + JSON-LD
1import { generateMeta } from "@forge42/seo-tools/remix/metadata";2import { product as productLD } from "@forge42/seo-tools/structured-data/product";3import { breadcrumbs } from "@forge42/seo-tools/structured-data/breadcrumb";45export const meta = ({ loaderData, location }) =>6generateMeta(7{8title: loaderData.product.name,9description: loaderData.product.description ?? "",10image: loaderData.productImages[0].url,11url: `https://localhost:5173${location.pathname}`,12},13[14{ "script:ld+json": productLD(/* …données produit… */) },15{ "script:ld+json": breadcrumbs(location.pathname, ["Accueil", "Collection", loaderData.product.name]) },16],17);
Explication :
generateMeta écrit <title>, <meta> et injecte deux scripts JSON-LD :
Product (prix, stock) + breadcrumb (meilleure navigation pour Google).
Page React
1<div className="prose">2<Markdown remarkPlugins={[remarkGfm]}>3{product.content}4</Markdown>5</div>
Pourquoi react-markdown ?
• SSR immédiat : le contenu est déjà HTML dans la réponse ;
• remark-gfm ajoute tableaux + todo-list GitHub style.
Tailwind Typography
1npm i @tailwindcss/typography
1@plugin "@tailwindcss/typography";
Ensuite la classe prose gère couleurs, tailles et espacements.
4 Breadcrumb + design responsive
Cardinalité :
- Desktop : image 4/3, H1 + price + bouton.
- Mobile : images avant le titre, burger menu reste utilisable.
1<nav aria-label="Breadcrumb" className="mb-8 text-sm">2<Link to="/" className="text-gray-500 hover:text-black">Accueil</Link>3<ChevronRight className="inline h-4 w-4 mx-1 text-gray-400" />4<Link to="/products" className="text-gray-500 hover:text-black">Collection</Link>5<ChevronRight className="inline h-4 w-4 mx-1 text-gray-400" />6<span className="text-gray-900">{product.name}</span>7</nav>
5 Tester : extension Meta SEO Inspector
- F12 → Onglet Elements :
<title>Chef Gordon 2…</title>+ meta OK. - Meta SEO Inspector : image OG, JSON-LD Product, breadcrumb valides.
- Schema Markup Validator : 0 erreur, 0 warning.
6 Commit & pull-request
1git add .2git commit -m "feat(product): page détail avec markdown & SEO"3git push -u origin 7-5-ajout-de-la-page-detail-du-produit
Merge ; la CI rebuild → staging → prod. Ton robot est en ligne, optimisé et indexable 🔥
À retenir
- Slug unique = URL lisible + clé pour
findUnique. - Champ
contentMarkdown +react-markdown= rédaction libre, rendu SSR. generateMeta+ JSON-LD = SEO complet sans duplicate code.- Breadcrumb améliore UX et rich snippet.
- Tailwind Typography → typographie propre en une classe.
Prochaine étape : dashboard admin pour gérer ces robots. À tout de suite !
Comprendre les concepts fondamentaux
Quelle est la principale différence entre les composants client et serveur dans React ?
Optimisation des performances
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Architecture des données
Quel hook permet de gérer les effets de bord dans un composant React ?