generateMetadata
Вы можете использовать объект metadata
или функцию generateMetadata
для определения метаданных.
Объект metadata
Для определения статических метаданных экспортируйте объект Metadata
из файла layout.js
или page.js
.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '...',
description: '...',
}
export default function Page() {}
export const metadata = {
title: '...',
description: '...',
}
export default function Page() {}
Полный список поддерживаемых опций смотрите в разделе Поля метаданных.
Функция generateMetadata
Динамические метаданные, зависящие от динамической информации, такие как текущие параметры маршрута, внешние данные или метаданные в родительских сегментах, могут быть заданы с помощью экспорта функции generateMetadata
, которая возвращает объект Metadata
.
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// чтение параметров маршрута
const { id } = await params
// получение данных
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// опциональное использование и расширение (а не замена) родительских метаданных
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) {
// чтение параметров маршрута
const { id } = await params
// получение данных
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// опциональное использование и расширение (а не замена) родительских метаданных
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
export default function Page({ params, searchParams }) {}
Полезно знать:
- Метаданные можно добавлять в файлы
layout.js
иpage.js
.- Next.js автоматически обработает метаданные и создаст соответствующие теги
<head>
для страницы.- Экспорт объекта
metadata
и функцииgenerateMetadata
поддерживается только в Server Components.- Нельзя экспортировать одновременно объект
metadata
и функциюgenerateMetadata
из одного сегмента маршрута.- Запросы
fetch
внутриgenerateMetadata
автоматически мемоизируются для одинаковых данных междуgenerateMetadata
,generateStaticParams
, Layouts, Pages и Server Components.- React
cache
можно использовать, еслиfetch
недоступен.- Файловые метаданные имеют более высокий приоритет и переопределяют объект
metadata
и функциюgenerateMetadata
.
Справочник
Параметры
Функция generateMetadata
принимает следующие параметры:
-
props
- Объект, содержащий параметры текущего маршрута:-
params
- Объект, содержащий параметры динамического маршрута от корневого сегмента до сегмента, из которого вызываетсяgenerateMetadata
. Примеры:Маршрут URL params
app/shop/[slug]/page.js
/shop/1
{ slug: '1' }
app/shop/[tag]/[item]/page.js
/shop/1/2
{ tag: '1', item: '2' }
app/shop/[...slug]/page.js
/shop/1/2
{ slug: ['1', '2'] }
-
searchParams
- Объект, содержащий параметры поиска текущего URL. Примеры:URL searchParams
/shop?a=1
{ a: '1' }
/shop?a=1&b=2
{ a: '1', b: '2' }
/shop?a=1&a=2
{ a: ['1', '2'] }
-
-
parent
- Промис с разрешёнными метаданными из родительских сегментов маршрута.
Возвращаемое значение
generateMetadata
должна возвращать объект Metadata
, содержащий одно или несколько полей метаданных.
Полезно знать:
- Если метаданные не зависят от информации во время выполнения, их следует определять с помощью статического объекта
metadata
, а неgenerateMetadata
.- Запросы
fetch
автоматически мемоизируются для одинаковых данных междуgenerateMetadata
,generateStaticParams
, Layouts, Pages и Server Components. Reactcache
можно использовать, еслиfetch
недоступен.searchParams
доступны только в сегментахpage.js
.- Методы Next.js
redirect()
иnotFound()
также можно использовать внутриgenerateMetadata
.
Поля метаданных
Поддерживаются следующие поля:
title
Атрибут title
используется для установки заголовка документа. Может быть определён как простая строка или необязательный шаблонный объект.
Строка
export const metadata = {
title: 'Next.js',
}
<title>Next.js</title>
default
title.default
можно использовать для предоставления резервного заголовка дочерним сегментам маршрута, которые не определяют title
.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
default: 'Acme',
},
}
import type { Metadata } from 'next'
export const metadata: Metadata = {}
// Вывод: <title>Acme</title>
template
title.template
можно использовать для добавления префикса или суффикса к titles
, определённым в дочерних сегментах маршрута.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
template: '%s | Acme',
default: 'Acme', // требуется по умолчанию при создании шаблона
},
}
export const metadata = {
title: {
template: '%s | Acme',
default: 'Acme', // требуется по умолчанию при создании шаблона
},
}
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'About',
}
// Вывод: <title>About | Acme</title>
export const metadata = {
title: 'About',
}
// Вывод: <title>About | Acme</title>
Полезно знать:
title.template
применяется к дочерним сегментам маршрута, а не к сегменту, в котором он определён. Это означает:
title.default
обязателен при добавленииtitle.template
.title.template
, определённый вlayout.js
, не будет применяться кtitle
, определённому вpage.js
того же сегмента маршрута.title.template
, определённый вpage.js
, не имеет эффекта, потому что страница всегда является конечным сегментом (у неё нет дочерних сегментов маршрута).
title.template
не имеет эффекта, если маршрут не определилtitle
илиtitle.default
.
absolute
title.absolute
можно использовать для предоставления заголовка, который игнорирует title.template
, установленный в родительских сегментах.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
template: '%s | Acme',
},
}
export const metadata = {
title: {
template: '%s | Acme',
},
}
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: {
absolute: 'About',
},
}
// Вывод: <title>About</title>
export const metadata = {
title: {
absolute: 'About',
},
}
// Вывод: <title>About</title>
Полезно знать:
layout.js
title
(строка) иtitle.default
определяют заголовок по умолчанию для дочерних сегментов (которые не определяют свой собственныйtitle
). Они будут дополнятьtitle.template
из ближайшего родительского сегмента, если он существует.title.absolute
определяет заголовок по умолчанию для дочерних сегментов. Он игнорируетtitle.template
из родительских сегментов.title.template
определяет новый шаблон заголовка для дочерних сегментов.
page.js
- Если страница не определяет свой собственный заголовок, будет использоваться заголовок ближайшего родителя.
title
(строка) определяет заголовок маршрута. Он будет дополнятьtitle.template
из ближайшего родительского сегмента, если он существует.title.absolute
определяет заголовок маршрута. Он игнорируетtitle.template
из родительских сегментов.title.template
не имеет эффекта вpage.js
, потому что страница всегда является конечным сегментом маршрута.
description
export const metadata = {
description: 'The React Framework for the Web',
}
<meta name="description" content="The React Framework for the Web" />
Другие поля
export const metadata = {
generator: 'Next.js',
applicationName: 'Next.js',
referrer: 'origin-when-cross-origin',
keywords: ['Next.js', 'React', 'JavaScript'],
authors: [{ name: 'Seb' }, { name: 'Josh', url: 'https://nextjs.org' }],
creator: 'Jiachi Liu',
publisher: 'Sebastian Markbåge',
formatDetection: {
email: false,
address: false,
telephone: false,
},
}
<meta name="application-name" content="Next.js" />
<meta name="author" content="Seb" />
<link rel="author" href="https://nextjs.org" />
<meta name="author" content="Josh" />
<meta name="generator" content="Next.js" />
<meta name="keywords" content="Next.js,React,JavaScript" />
<meta name="referrer" content="origin-when-cross-origin" />
<meta name="color-scheme" content="dark" />
<meta name="creator" content="Jiachi Liu" />
<meta name="publisher" content="Sebastian Markbåge" />
<meta name="format-detection" content="telephone=no, address=no, email=no" />
metadataBase
metadataBase
- это удобная опция для установки базового префикса URL для полей metadata
, которые требуют полного URL.
metadataBase
позволяет URL-полямmetadata
, определённым в текущем сегменте маршрута и ниже, использовать относительный путь вместо обязательного абсолютного URL.- Относительный путь поля будет объединён с
metadataBase
для формирования полного URL.
export const metadata = {
metadataBase: new URL('https://acme.com'),
alternates: {
canonical: '/',
languages: {
'en-US': '/en-US',
'de-DE': '/de-DE',
},
},
openGraph: {
images: '/og-image.png',
},
}
<link rel="canonical" href="https://acme.com" />
<link rel="alternate" hreflang="en-US" href="https://acme.com/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://acme.com/de-DE" />
<meta property="og:image" content="https://acme.com/og-image.png" />
Полезно знать:
metadataBase
обычно устанавливается в корневомapp/layout.js
, чтобы применяться к URL-полямmetadata
во всех маршрутах.- Все URL-поля
metadata
, требующие абсолютных URL, могут быть настроены с помощью опцииmetadataBase
.metadataBase
может содержать поддомен, напримерhttps://app.acme.com
, или базовый путь, напримерhttps://acme.com/start/from/here
.- Если поле
metadata
предоставляет абсолютный URL,metadataBase
будет проигнорирован.- Использование относительного пути в URL-поле
metadata
без настройкиmetadataBase
вызовет ошибку сборки.- Next.js нормализует дублирующиеся слеши между
metadataBase
(например,https://acme.com/
) и относительным полем (например,/path
) до одного слеша (например,https://acme.com/path
).
Композиция URL
Композиция URL отдаёт предпочтение намерениям разработчика перед семантикой обхода директорий по умолчанию.
- Конечные слеши между
metadataBase
и полямиmetadata
нормализуются. - "Абсолютный" путь в поле
metadata
(который обычно заменяет весь путь URL) рассматривается как "относительный" путь (начиная с концаmetadataBase
).
Например, для следующего metadataBase
:
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://acme.com'),
}
export const metadata = {
metadataBase: new URL('https://acme.com'),
}
Любые поля metadata
, которые наследуют вышеуказанный metadataBase
и устанавливают собственное значение, будут разрешены следующим образом:
Поле metadata | Разрешённый URL |
---|---|
/ | https://acme.com |
./ | https://acme.com |
payments | https://acme.com/payments |
/payments | https://acme.com/payments |
./payments | https://acme.com/payments |
../payments | https://acme.com/payments |
https://beta.acme.com/payments | https://beta.acme.com/payments |
openGraph
export const metadata = {
openGraph: {
title: 'Next.js',
description: 'The React Framework for the Web',
url: 'https://nextjs.org',
siteName: 'Next.js',
images: [
{
url: 'https://nextjs.org/og.png', // Должен быть абсолютным URL
width: 800,
height: 600,
},
{
url: 'https://nextjs.org/og-alt.png', // Должен быть абсолютным URL
width: 1800,
height: 1600,
alt: 'Мой альтернативный текст',
},
],
videos: [
{
url: 'https://nextjs.org/video.mp4', // Должен быть абсолютным URL
width: 800,
height: 600,
},
],
audio: [
{
url: 'https://nextjs.org/audio.mp3', // Должен быть абсолютным URL
},
],
locale: 'en_US',
type: 'website',
},
}
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:url" content="https://nextjs.org/" />
<meta property="og:site_name" content="Next.js" />
<meta property="og:locale" content="en_US" />
<meta property="og:image" content="https://nextjs.org/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
<meta property="og:image" content="https://nextjs.org/og-alt.png" />
<meta property="og:image:width" content="1800" />
<meta property="og:image:height" content="1600" />
<meta property="og:image:alt" content="Мой альтернативный текст" />
<meta property="og:video" content="https://nextjs.org/video.mp4" />
<meta property="og:video:width" content="800" />
<meta property="og:video:height" content="600" />
<meta property="og:audio" content="https://nextjs.org/audio.mp3" />
<meta property="og:type" content="website" />
export const metadata = {
openGraph: {
title: 'Next.js',
description: 'The React Framework for the Web',
type: 'article',
publishedTime: '2023-01-01T00:00:00.000Z',
authors: ['Seb', 'Josh'],
},
}
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2023-01-01T00:00:00.000Z" />
<meta property="article:author" content="Seb" />
<meta property="article:author" content="Josh" />
Полезно знать:
- Для изображений Open Graph может быть удобнее использовать файловый Metadata API. Вместо синхронизации конфигурации с реальными файлами, файловый API автоматически сгенерирует правильные метаданные.
robots
import type { Metadata } from 'next'
export const metadata: Metadata = {
robots: {
index: true,
follow: true,
nocache: false,
googleBot: {
index: true,
follow: true,
noimageindex: false,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
}
<meta name="robots" content="index, follow" />
<meta
name="googlebot"
content="index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1"
/>
icons
Полезно знать: Рекомендуем использовать файловый Metadata API для иконок, где это возможно. Вместо синхронизации конфигурации с реальными файлами, файловый API автоматически сгенерирует правильные метаданные.
export const metadata = {
icons: {
icon: '/icon.png',
shortcut: '/shortcut-icon.png',
apple: '/apple-icon.png',
other: {
rel: 'apple-touch-icon-precomposed',
url: '/apple-touch-icon-precomposed.png',
},
},
}
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
rel="apple-touch-icon-precomposed"
href="/apple-touch-icon-precomposed.png"
/>
export const metadata = {
icons: {
icon: [
{ url: '/icon.png' },
new URL('/icon.png', 'https://example.com'),
{ url: '/icon-dark.png', media: '(prefers-color-scheme: dark)' },
],
shortcut: ['/shortcut-icon.png'],
apple: [
{ url: '/apple-icon.png' },
{ url: '/apple-icon-x3.png', sizes: '180x180', type: 'image/png' },
],
other: [
{
rel: 'apple-touch-icon-precomposed',
url: '/apple-touch-icon-precomposed.png',
},
],
},
}
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="icon" href="https://example.com/icon.png" />
<link rel="icon" href="/icon-dark.png" media="(prefers-color-scheme: dark)" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
rel="apple-touch-icon-precomposed"
href="/apple-touch-icon-precomposed.png"
/>
<link
rel="apple-touch-icon"
href="/apple-icon-x3.png"
sizes="180x180"
type="image/png"
/>
Полезно знать: Мета-теги
msapplication-*
больше не поддерживаются в Chromium-сборках Microsoft Edge и больше не нужны.
themeColor
Устарело: Опция
themeColor
вmetadata
устарела в Next.js 14. Вместо неё используйтеviewport
конфигурацию.
colorScheme
Устарело: Опция
colorScheme
вmetadata
устарела в Next.js 14. Вместо неё используйтеviewport
конфигурацию.
manifest
Манифест веб-приложения, как определено в спецификации Web Application Manifest.
export const metadata = {
manifest: 'https://nextjs.org/manifest.json',
}
<link rel="manifest" href="https://nextjs.org/manifest.json" />
twitter
Спецификация Twitter используется (удивительно) не только для X (ранее известного как Twitter).
Подробнее о Twitter Card markup reference.
export const metadata = {
twitter: {
card: 'summary_large_image',
title: 'Next.js',
description: 'The React Framework for the Web',
siteId: '1467726470533754880',
creator: '@nextjs',
creatorId: '1467726470533754880',
images: ['https://nextjs.org/og.png'], // Должен быть абсолютным URL
},
}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
export const metadata = {
twitter: {
card: 'app',
title: 'Next.js',
description: 'The React Framework for the Web',
siteId: '1467726470533754880',
creator: '@nextjs',
creatorId: '1467726470533754880',
images: {
url: 'https://nextjs.org/og.png',
alt: 'Next.js Logo',
},
app: {
name: 'twitter_app',
id: {
iphone: 'twitter_app://iphone',
ipad: 'twitter_app://ipad',
googleplay: 'twitter_app://googleplay',
},
url: {
iphone: 'https://iphone_url',
ipad: 'https://ipad_url',
},
},
},
}
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:card" content="app" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
<meta name="twitter:image:alt" content="Next.js Logo" />
<meta name="twitter:app:name:iphone" content="twitter_app" />
<meta name="twitter:app:id:iphone" content="twitter_app://iphone" />
<meta name="twitter:app:id:ipad" content="twitter_app://ipad" />
<meta name="twitter:app:id:googleplay" content="twitter_app://googleplay" />
<meta name="twitter:app:url:iphone" content="https://iphone_url" />
<meta name="twitter:app:url:ipad" content="https://ipad_url" />
<meta name="twitter:app:name:ipad" content="twitter_app" />
<meta name="twitter:app:name:googleplay" content="twitter_app" />
viewport
Устарело: Опция
viewport
вmetadata
устарела в Next.js 14. Вместо неё используйтеviewport
конфигурацию.
verification
export const metadata = {
verification: {
google: 'google',
yandex: 'yandex',
yahoo: 'yahoo',
other: {
me: ['my-email', 'my-link'],
},
},
}
<meta name="google-site-verification" content="google" />
<meta name="y_key" content="yahoo" />
<meta name="yandex-verification" content="yandex" />
<meta name="me" content="my-email" />
<meta name="me" content="my-link" />
appleWebApp
export const metadata = {
itunes: {
appId: 'myAppStoreID',
appArgument: 'myAppArgument',
},
appleWebApp: {
title: 'Apple Web App',
statusBarStyle: 'black-translucent',
startupImage: [
'/assets/startup/apple-touch-startup-image-768x1004.png',
{
url: '/assets/startup/apple-touch-startup-image-1536x2008.png',
media: '(device-width: 768px) and (device-height: 1024px)',
},
],
},
}
<meta
name="apple-itunes-app"
content="app-id=myAppStoreID, app-argument=myAppArgument"
/>
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Apple Web App" />
<link
href="/assets/startup/apple-touch-startup-image-768x1004.png"
rel="apple-touch-startup-image"
/>
<link
href="/assets/startup/apple-touch-startup-image-1536x2008.png"
media="(device-width: 768px) and (device-height: 1024px)"
rel="apple-touch-startup-image"
/>
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
alternates
export const metadata = {
alternates: {
canonical: 'https://nextjs.org',
languages: {
'en-US': 'https://nextjs.org/en-US',
'de-DE': 'https://nextjs.org/de-DE',
},
media: {
'only screen and (max-width: 600px)': 'https://nextjs.org/mobile',
},
types: {
'application/rss+xml': 'https://nextjs.org/rss',
},
},
}
<link rel="canonical" href="https://nextjs.org" />
<link rel="alternate" hreflang="en-US" href="https://nextjs.org/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://nextjs.org/de-DE" />
<link
rel="alternate"
media="only screen and (max-width: 600px)"
href="https://nextjs.org/mobile"
/>
<link
rel="alternate"
type="application/rss+xml"
href="https://nextjs.org/rss"
/>
appLinks
export const metadata = {
appLinks: {
ios: {
url: 'https://nextjs.org/ios',
app_store_id: 'app_store_id',
},
android: {
package: 'com.example.android/package',
app_name: 'app_name_android',
},
web: {
url: 'https://nextjs.org/web',
should_fallback: true,
},
},
}
<meta property="al:ios:url" content="https://nextjs.org/ios" />
<meta property="al:ios:app_store_id" content="app_store_id" />
<meta property="al:android:package" content="com.example.android/package" />
<meta property="al:android:app_name" content="app_name_android" />
<meta property="al:web:url" content="https://nextjs.org/web" />
<meta property="al:web:should_fallback" content="true" />
archives
Описывает коллекцию записей, документов или других материалов, представляющих исторический интерес (источник).
export const metadata = {
archives: ['https://nextjs.org/13'],
}
<link rel="archives" href="https://nextjs.org/13" />
assets
export const metadata = {
assets: ['https://nextjs.org/assets'],
}
<link rel="assets" href="https://nextjs.org/assets" />
bookmarks
export const metadata = {
bookmarks: ['https://nextjs.org/13'],
}
<link rel="bookmarks" href="https://nextjs.org/13" />
category
export const metadata = {
category: 'technology',
}
<meta name="category" content="technology" />
facebook
Вы можете подключить приложение Facebook или аккаунт Facebook к вашей веб-странице для определённых Facebook Social Plugins Документация Facebook
Полезно знать: Можно указать либо appId, либо admins, но не оба одновременно.
export const metadata = {
facebook: {
appId: '12345678',
},
}
<meta property="fb:app_id" content="12345678" />
export const metadata = {
facebook: {
admins: '12345678',
},
}
<meta property="fb:admins" content="12345678" />
Если нужно сгенерировать несколько мета-тегов fb:admins, можно использовать массив.
export const metadata = {
facebook: {
admins: ['12345678', '87654321'],
},
}
<meta property="fb:admins" content="12345678" />
<meta property="fb:admins" content="87654321" />
pinterest
Вы можете включить или отключить Pinterest Rich Pins на вашей веб-странице.
export const metadata = {
pinterest: {
richPin: true,
},
}
<meta name="pinterest-rich-pin" content="true" />
other
Все варианты метаданных должны быть покрыты встроенной поддержкой. Однако могут быть пользовательские мета-теги, специфичные для вашего сайта, или новые мета-теги, только что выпущенные. Вы можете использовать опцию other
для рендеринга любых пользовательских мета-тегов.
export const metadata = {
other: {
custom: 'meta',
},
}
<meta name="custom" content="meta" />
Если нужно сгенерировать несколько мета-тегов с одинаковым ключом, можно использовать массив.
export const metadata = {
other: {
custom: ['meta1', 'meta2'],
},
}
<meta name="custom" content="meta1" /> <meta name="custom" content="meta2" />
Неподдерживаемые метаданные
Следующие типы метаданных в настоящее время не имеют встроенной поддержки. Однако их всё ещё можно отрендерить в самом layout или странице.
Типы
Вы можете добавить проверку типов к метаданным, используя тип Metadata
. Если вы используете встроенный плагин TypeScript в вашей IDE, вам не нужно добавлять тип вручную, но вы всё равно можете явно указать его при необходимости.
Объект metadata
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Next.js',
}
Функция generateMetadata
Обычная функция
import type { Metadata } from 'next'
export function generateMetadata(): Metadata {
return {
title: 'Next.js',
}
}
Асинхронная функция
import type { Metadata } from 'next'
export async function generateMetadata(): Promise<Metadata> {
return {
title: 'Next.js',
}
}
С параметрами сегментов
import type { Metadata } from 'next'
type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export function generateMetadata({ params, searchParams }: Props): Metadata {
return {
title: 'Next.js',
}
}
export default function Page({ params, searchParams }: Props) {}
С родительскими метаданными
import type { Metadata, ResolvingMetadata } from 'next'
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
return {
title: 'Next.js',
}
}
JavaScript-проекты
Для JavaScript-проектов вы можете использовать JSDoc для добавления проверки типов.
/** @type {import("next").Metadata} */
export const metadata = {
title: 'Next.js',
}
Метаданные | Рекомендация |
---|---|
<meta http-equiv="..."> | Используйте соответствующие HTTP-заголовки через redirect() , Middleware, Security Headers |
<base> | Рендерите тег непосредственно в макете или странице. |
<noscript> | Рендерите тег непосредственно в макете или странице. |
<style> | Подробнее о стилях в Next.js. |
<script> | Подробнее об использовании скриптов. |
<link rel="stylesheet" /> | Импортируйте таблицы стилей напрямую в макет или страницу. |
<link rel="preload /> | Используйте метод preload ReactDOM |
<link rel="preconnect" /> | Используйте метод preconnect ReactDOM |
<link rel="dns-prefetch" /> | Используйте метод prefetchDNS ReactDOM |
Ресурсные подсказки
Элемент <link>
имеет ряд ключевых слов rel
, которые можно использовать для указания браузеру, что внешний ресурс, вероятно, понадобится. Браузер использует эту информацию для применения оптимизаций предзагрузки в зависимости от ключевого слова.
Хотя API метаданных напрямую не поддерживает эти подсказки, вы можете использовать новые методы ReactDOM
для безопасного их добавления в <head>
документа.
'use client'
import ReactDOM from 'react-dom'
export function PreloadResources() {
ReactDOM.preload('...', { as: '...' })
ReactDOM.preconnect('...', { crossOrigin: '...' })
ReactDOM.prefetchDNS('...')
return '...'
}
'use client'
import ReactDOM from 'react-dom'
export function PreloadResources() {
ReactDOM.preload('...', { as: '...' })
ReactDOM.preconnect('...', { crossOrigin: '...' })
ReactDOM.prefetchDNS('...')
return '...'
}
<link rel="preload">
Начинает загрузку ресурса на раннем этапе жизненного цикла рендеринга страницы (в браузере). Документация MDN.
ReactDOM.preload(href: string, options: { as: string })
<link rel="preload" href="..." as="..." />
<link rel="preconnect">
Предварительно инициирует соединение с источником. Документация MDN.
ReactDOM.preconnect(href: string, options?: { crossOrigin?: string })
<link rel="preconnect" href="..." crossorigin />
<link rel="dns-prefetch">
Пытается разрешить доменное имя до запроса ресурсов. Документация MDN.
ReactDOM.prefetchDNS(href: string)
<link rel="dns-prefetch" href="..." />
Полезно знать:
- В настоящее время эти методы поддерживаются только в клиентских компонентах, которые всё равно рендерятся на стороне сервера при первоначальной загрузке страницы.
- Встроенные функции Next.js, такие как
next/font
,next/image
иnext/script
, автоматически обрабатывают соответствующие ресурсные подсказки.
Поведение
Поля по умолчанию
Есть два тега meta
по умолчанию, которые всегда добавляются, даже если маршрут не определяет метаданные:
- Тег meta charset устанавливает кодировку символов для веб-сайта.
- Тег meta viewport устанавливает ширину и масштаб области просмотра для адаптации под разные устройства.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Полезно знать: Вы можете переопределить тег
viewport
по умолчанию.
Потоковая передача метаданных
Метаданные, возвращаемые generateMetadata
, передаются клиенту потоком. Это позволяет Next.js встраивать метаданные в HTML, как только они разрешаются.
Поскольку метаданные страницы в первую очередь предназначены для ботов и краулеров, Next.js будет передавать метаданные для ботов, которые могут выполнять JavaScript и проверять полный DOM страницы (например, Googlebot
). Однако метаданные будут блокировать рендеринг страницы для ботов с ограниченными возможностями HTML (например, Twitterbot
), так как они не могут выполнять JavaScript при сканировании.
Next.js автоматически определяет пользовательский агент входящих запросов, чтобы решить, передавать ли метаданные потоком или использовать блокирующие метаданные.
Если вам нужно настроить этот список, вы можете определить его вручную, используя опцию htmlLimitedBots
в next.config.js
. Next.js гарантирует, что пользовательские агенты, соответствующие этому регулярному выражению, получат блокирующие метаданные при запросе вашей веб-страницы.
import type { NextConfig } from 'next'
const config: NextConfig = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
export default config
module.exports = {
htmlLimitedBots: /MySpecialBot|MyAnotherSpecialBot|SimpleCrawler/,
}
Указание конфигурации htmlLimitedBots
переопределит список Next.js по умолчанию, предоставляя вам полный контроль над тем, какие пользовательские агенты должны использовать это поведение. Это продвинутая настройка, и в большинстве случаев достаточно значений по умолчанию.
Порядок
Метаданные оцениваются в порядке от корневого сегмента до сегмента, ближайшего к конечному page.js
. Например:
app/layout.tsx
(Корневой макет)app/blog/layout.tsx
(Вложенный макет блога)app/blog/[slug]/page.tsx
(Страница блога)
Объединение
Следуя порядку оценки, объекты метаданных, экспортированные из нескольких сегментов одного маршрута, поверхностно объединяются для формирования окончательного вывода метаданных маршрута. Дублирующиеся ключи заменяются в соответствии с их порядком.
Это означает, что метаданные с вложенными полями, такими как openGraph
и robots
, определённые в более раннем сегменте, перезаписываются последним сегментом, который их определяет.
Перезапись полей
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
}
export const metadata = {
title: 'Blog',
openGraph: {
title: 'Blog',
},
}
// Вывод:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />
В примере выше:
title
изapp/layout.js
заменяется наtitle
изapp/blog/page.js
.- Все поля
openGraph
изapp/layout.js
заменяются вapp/blog/page.js
, потому чтоapp/blog/page.js
устанавливает метаданныеopenGraph
. Обратите внимание на отсутствиеopenGraph.description
.
Если вы хотите поделиться некоторыми вложенными полями между сегментами, перезаписывая другие, вы можете вынести их в отдельную переменную:
export const openGraphImage = { images: ['http://...'] }
import { openGraphImage } from './shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Home',
},
}
import { openGraphImage } from '../shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'About',
},
}
В примере выше изображение OG совместно используется app/layout.js
и app/about/page.js
, в то время как заголовки различаются.
Наследование полей
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
}
export const metadata = {
title: 'About',
}
// Вывод:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />
Примечания
title
изapp/layout.js
заменяется наtitle
изapp/about/page.js
.- Все поля
openGraph
изapp/layout.js
наследуются вapp/about/page.js
, потому чтоapp/about/page.js
не устанавливает метаданныеopenGraph
.
История версий
Версия | Изменения |
---|---|
v15.2.0 | Добавлена поддержка потоковой передачи для generateMetadata . |
v13.2.0 | viewport , themeColor и colorScheme устарели в пользу конфигурации viewport . |
v13.2.0 | Введены metadata и generateMetadata . |