Métadonnées
Next.js propose une API Metadata qui permet de définir les métadonnées de votre application (comme les balises meta
et link
à l'intérieur de l'élément HTML head
) pour améliorer le référencement naturel (SEO) et la partageabilité web.
Il existe deux façons d'ajouter des métadonnées à votre application :
- Métadonnées basées sur la configuration : Exportez un objet
metadata
statique ou une fonction dynamiquegenerateMetadata
dans un fichierlayout.js
oupage.js
. - Métadonnées basées sur les fichiers : Ajoutez des fichiers spéciaux statiques ou générés dynamiquement aux segments de route.
Avec ces deux options, Next.js générera automatiquement les éléments <head>
pertinents pour vos pages. Vous pouvez également créer des images OG dynamiques en utilisant le constructeur ImageResponse
.
Métadonnées statiques
Pour définir des métadonnées statiques, exportez un objet Metadata
depuis un fichier layout.js
ou un fichier page.js
statique.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '...',
description: '...',
}
export default function Page() {}
export const metadata = {
title: '...',
description: '...',
}
export default function Page() {}
Pour toutes les options disponibles, consultez la Référence API.
Métadonnées dynamiques
Vous pouvez utiliser la fonction generateMetadata
pour récupérer (fetch
) des métadonnées nécessitant des valeurs dynamiques.
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: { id: string }
searchParams: { [key: string]: string | string[] | undefined }
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// lire les paramètres de route
const id = params.id
// récupérer les données
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// accéder et étendre (plutôt que remplacer) les métadonnées parentes
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
export default function Page({ params, searchParams }: Props) {}
export async function generateMetadata({ params, searchParams }, parent) {
// lire les paramètres de route
const id = params.id
// récupérer les données
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// accéder et étendre (plutôt que remplacer) les métadonnées parentes
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
export default function Page({ params, searchParams }) {}
Pour tous les paramètres disponibles, consultez la Référence API.
Bon à savoir :
- Les métadonnées statiques et dynamiques via
generateMetadata
sont uniquement prises en charge dans les composants serveur.- Les requêtes
fetch
sont automatiquement mémoïsées pour les mêmes données dansgenerateMetadata
,generateStaticParams
, les mises en page (Layouts), les pages (Pages) et les composants serveur. Lecache
de React peut être utilisé sifetch
n'est pas disponible.- Next.js attendra que la récupération de données dans
generateMetadata
soit terminée avant de diffuser l'interface utilisateur au client. Cela garantit que la première partie d'une réponse en streaming inclut les balises<head>
.
Métadonnées basées sur les fichiers
Ces fichiers spéciaux sont disponibles pour les métadonnées :
- favicon.ico, apple-icon.jpg et icon.jpg
- opengraph-image.jpg et twitter-image.jpg
- robots.txt
- sitemap.xml
Vous pouvez les utiliser pour des métadonnées statiques ou générer ces fichiers dynamiquement avec du code.
Pour des exemples et des implémentations, consultez la Référence API des fichiers de métadonnées et la Génération d'images dynamiques.
Comportement
Les métadonnées basées sur les fichiers ont une priorité plus élevée et remplaceront toutes les métadonnées basées sur la configuration.
Champs par défaut
Il y a deux balises meta
par défaut qui sont toujours ajoutées, même si une route ne définit pas de métadonnées :
- La balise meta charset définit l'encodage des caractères du site.
- La balise meta viewport définit la largeur et l'échelle de la fenêtre d'affichage pour s'adapter à différents appareils.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Bon à savoir : Vous pouvez remplacer la balise meta
viewport
par défaut.
Ordre d'évaluation
Les métadonnées sont évaluées dans l'ordre, en commençant par le segment racine jusqu'au segment le plus proche du fichier page.js
final. Par exemple :
app/layout.tsx
(Mise en page racine)app/blog/layout.tsx
(Mise en page imbriquée du blog)app/blog/[slug]/page.tsx
(Page du blog)
Fusion
En suivant l'ordre d'évaluation, les objets Metadata exportés depuis plusieurs segments de la même route sont fusionnés superficiellement pour former le résultat final des métadonnées d'une route. Les clés en double sont remplacées en fonction de leur ordre.
Cela signifie que les métadonnées avec des champs imbriqués comme openGraph
et robots
définis dans un segment précédent sont écrasés par le dernier segment qui les définit.
Remplacer des champs
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme est un...',
},
}
export const metadata = {
title: 'Blog',
openGraph: {
title: 'Blog',
},
}
// Résultat :
// <title>Blog</title>
// <meta property="og:title" content="Blog" />
Dans l'exemple ci-dessus :
- Le
title
deapp/layout.js
est remplacé par letitle
dansapp/blog/page.js
. - Tous les champs
openGraph
deapp/layout.js
sont remplacés dansapp/blog/page.js
carapp/blog/page.js
définit les métadonnéesopenGraph
. Notez l'absence deopenGraph.description
.
Si vous souhaitez partager certains champs imbriqués entre les segments tout en en remplaçant d'autres, vous pouvez les extraire dans une variable séparée :
export const openGraphImage = { images: ['http://...'] }
import { openGraphImage } from './shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Accueil',
},
}
import { openGraphImage } from '../shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'À propos',
},
}
Dans l'exemple ci-dessus, l'image OG est partagée entre app/layout.js
et app/about/page.js
tandis que les titres sont différents.
Hériter des champs
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme est un...',
},
}
export const metadata = {
title: 'À propos',
}
// Résultat :
// <title>À propos</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme est un..." />
Notes
- Le
title
deapp/layout.js
est remplacé par letitle
dansapp/about/page.js
. - Tous les champs
openGraph
deapp/layout.js
sont hérités dansapp/about/page.js
carapp/about/page.js
ne définit pas de métadonnéesopenGraph
.
Génération d'images dynamiques
Le constructeur ImageResponse
permet de générer des images dynamiques en utilisant JSX et CSS. C'est utile pour créer des images pour les réseaux sociaux comme les images Open Graph, les cartes Twitter, etc.
ImageResponse
utilise le Edge Runtime, et Next.js ajoute automatiquement les en-têtes corrects pour les images mises en cache à la périphérie (edge), améliorant ainsi les performances et réduisant les recalculs.
Pour l'utiliser, vous pouvez importer ImageResponse
depuis next/og
:
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export async function GET() {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
}}
>
Bonjour le monde !
</div>
),
{
width: 1200,
height: 600,
}
)
}
ImageResponse
s'intègre bien avec d'autres API Next.js, y compris les Route Handlers et les métadonnées basées sur les fichiers. Par exemple, vous pouvez utiliser ImageResponse
dans un fichier opengraph-image.tsx
pour générer des images Open Graph au moment de la construction ou dynamiquement au moment de la requête.
ImageResponse
prend en charge les propriétés CSS courantes, y compris flexbox et le positionnement absolu, les polices personnalisées, le retour à la ligne du texte, le centrage et les images imbriquées. Voir la liste complète des propriétés CSS prises en charge.
Bon à savoir :
- Des exemples sont disponibles dans le Vercel OG Playground.
ImageResponse
utilise @vercel/og, Satori et Resvg pour convertir HTML et CSS en PNG.- Seul le Edge Runtime est pris en charge. Le runtime Node.js par défaut ne fonctionnera pas.
- Seuls flexbox et un sous-ensemble de propriétés CSS sont pris en charge. Les mises en page avancées (par exemple
display: grid
) ne fonctionneront pas.- Taille maximale du bundle de
500KB
. La taille du bundle inclut votre JSX, CSS, polices, images et tout autre actif. Si vous dépassez cette limite, envisagez de réduire la taille des actifs ou de les récupérer au moment de l'exécution.- Seuls les formats de police
ttf
,otf
etwoff
sont pris en charge. Pour maximiser la vitesse d'analyse des polices, préférezttf
ouotf
àwoff
.
JSON-LD
JSON-LD est un format pour les données structurées qui peut être utilisé par les moteurs de recherche pour comprendre votre contenu. Par exemple, vous pouvez l'utiliser pour décrire une personne, un événement, une organisation, un film, un livre, une recette et bien d'autres types d'entités.
Notre recommandation actuelle pour JSON-LD est de rendre les données structurées sous forme de balise <script>
dans vos composants layout.js
ou page.js
. Par exemple :
export default async function Page({ params }) {
const product = await getProduct(params.id)
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.name,
image: product.image,
description: product.description,
}
return (
<section>
{/* Ajoutez JSON-LD à votre page */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
)
}
export default async function Page({ params }) {
const product = await getProduct(params.id)
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.name,
image: product.image,
description: product.description,
}
return (
<section>
{/* Ajoutez JSON-LD à votre page */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
)
}
Vous pouvez valider et tester vos données structurées avec le Rich Results Test de Google ou le validateur générique Schema Markup Validator.
Vous pouvez typer votre JSON-LD avec TypeScript en utilisant des packages communautaires comme schema-dts
:
import { Product, WithContext } from 'schema-dts'
const jsonLd: WithContext<Product> = {
'@context': 'https://schema.org',
'@type': 'Product',
name: 'Autocollant Next.js',
image: 'https://nextjs.org/imgs/sticker.png',
description: 'Dynamique à la vitesse du statique.',
}