import { cache } from 'react';
import { Metadata } from 'next';
// React cache previne interogările duble în DB
const getProduct = cache(async (id: string) => {
const res = await fetch(`https://api.exemplu.ro/products/${id}`);
if (!res.ok) return null;
return res.json();
});
export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
const product = await getProduct(params.id);
if (!product) return { title: 'Produs nelocalizat' };
return {
title: `${product.title} - Magazin Online`,
description: product.description,
openGraph: {
images: [`/api/og?title=${encodeURIComponent(product.title)}`],
},
};
}Hai să vorbim direct despre cum facem SEO dinamic în Next.js fără să ne dăm cu capul de pereți. Am trecut recent un proiect de e-commerce cu peste 12.000 de produse active pe noul flux de metadata din Next.js și am învățat câteva lecții destul de dure pe pielea mea. Dacă nu ești atent, o configurație greșită îți poate distruge performanța sau, mai rău, îți poate trimite pagini goale în Google Search Console.
Capcana dublului fetch în generateMetadata
Trecerea de la vechiul <Head> la funcția generateMetadata din App Router e un pas înainte uriaș pentru că totul e tipizat și rulează strict pe server. Totuși, prima greșeală pe care am făcut-o a fost să apelez baza de date și în metadata, și în componenta paginii.
Dacă folosești fetch-ul nativ, Next.js face deduplicare automat. Dar ce te faci dacă folosești un ORM gen Prisma sau Drizzle direct? Aici intervine funcția cache din React. Am implementat o funcție utilitară simplă care învelește apelul de DB. Fără asta, baza noastră de date primea de două ori mai multe interogări pe fiecare vizită, iar timpul de răspuns crescuse cu aproape 40%.
Imagini OG dinamice fără să îți blochezi serverul
Pentru imagini de social media (Open Graph) generate dinamic, Next.js ne pune la dispoziție ImageResponse. E o chestie super elegantă bazată pe Satori, dar consumă CPU în draci la runtime.
La proiectul de care vă spuneam, generarea unei imagini OG pe baza numelui produsului și a prețului adăuga aproape 300ms la request-ul inițial dacă nu era în cache. Soluția sinceră? Nu generați imagini OG dinamice direct pe serverul de producție fără un CDN solid în față. Noi am configurat reguli stricte de cache în Cloudflare pentru ruta de /api/og ca să ne asigurăm că o imagine se generează o singură dată și apoi e servită instant publicului și roboților de indexare.
JSON-LD și datele structurate
Mulți devi încearcă să bage JSON-LD în obiectul returnat de generateMetadata. Nu faceți asta, nu acolo îi este locul. Cel mai curat mod de a trimite date structurate către Google în Next.js este să injectați un tag script direct în componenta paginii (Server Component).
E o metodă extrem de simplă care nu blochează randarea metadata-ului global și îți permite să folosești fix aceleași date pe care le randezi deja în HTML. Google îl citește perfect, iar codul tău rămâne modular.
Trade-off-ul de performanță pe care trebuie să-l accepți
Funcția generateMetadata blochează randarea paginii. Până când promisiunea returnată de ea nu este rezolvată, utilizatorul va vedea doar un ecran alb sau, în cel mai bun caz, scheletul din loading.js.
De aceea, regula mea de aur este: în metadata facem doar query-uri ultra-rapide. Nu trageți asocieri inutile din baza de date, nu calculați stocuri sau reduceri complexe acolo. Aveți nevoie doar de titlu, descriere și URL-ul imaginii. Am reușit să scădem TTFB-ul (Time to First Byte) de la 850ms la sub 180ms doar prin curățarea query-urilor din metadata.
Voi cum gestionați caching-ul pentru metadata în proiectele mari? Mergeți pe deduplicarea nativă din Next sau preferați să pasați datele printr-un sistem extern de caching?