메타데이터는 HTML 문서의 <head>
에 포함되어, 해당 웹 페이지에 대한 정보를 제공한다. 검색 엔진 최적화(SEO)에 영향을 주기 때문에 중요하다.
아래는 메타데이터의 예시이다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="description" content="웹사이트 설명">
<meta name="keywords" content="키워드1, 키워드2">
<meta name="author" content="저자 이름">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>웹사이트 제목</title>
</head>
<body>
<h1>환영합니다!</h1>
</body>
</html>
Next.js 14에서 메타데이터를 추가하는 방법은 두 가지가 있다. 아래 옵션을 사용하면 Next.js가 자동으로 페이지에 관련 <head>
를 생성한다.
metadata
객체나 동적 generateMetadata
함수를 사용한다.정적 메타데이터를 정의하려면, app
디렉토리의 layout.tsx
또는 page.tsx
에 다음과 같이 설정하면 된다.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '...',
description: '...',
}
generateMetadata
함수를 사용해 동적으로 설정할 수도 있다.
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> {
const product = await fetch(`https://.../${params.id}`).then((res) => res.json())
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
public
디렉토리에 다음과 같은 특수 파일을 사용할 수 있다.
favicon.ico
, apple-icon.jpg
, icon.jpg
opengraph-image.jpg
,twitter-image.jpg
robots.txt
sitemap.xml
title
description
metadataBase
openGraph
robots
icons
manifest
viewport
title
은 제목을 설정한다.
export const metadata = {
title: 'Next.js',
}
<title>Next.js</title>
title
에는 default
, template
, absolute
세 가지 객체가 있다.
title.default
는 title을 정의하지 않는 자식 세그먼트에 대체 제목을 설정한다.export const metadata: Metadata = {
title: {
default: 'Acme',
},
}
title.template
는 자식 세그먼트에 접두사나 접미사를 추가하는데 사용한다.// app/layout.tsx
export const metadata: Metadata = {
title: {
template: '%s | Acme',
default: 'Acme', // 템플릿을 만들 땐 deault를 설정해야 한다.
},
}
// app/about/page.tsx
export const metadata: Metadata = {
title: 'About',
}
// Output: <title>About | Acme</title>
title.absolute
는 부모 세그먼트의 template
를 무시한다.export const metadata: Metadata = {
title: {
absolute: 'About',
},
}
// Output: <title>About</title>
메타데이터를 정의하지 않더라도 다음 두 태그는 기본으로 설정된다. 덮어쓰는 것도 가능하다.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
메타데이터는 루트 세그먼트부터 시작해 최종 page
세그먼트까지 순서대로 평가된다. 순서에 따라, 동일한 경로의 여러 세그먼트에서 보내진 메타데이터 객체는 얕게 병합되어 최종 메타데이터를 출력한다. 중복된 내용은 마지막 세그먼트에서 정의된 메타데이터로 덮어쓰여진다.
<!-- app/layout.js -->
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
}
<!-- app/blog/page.js -->
export const metadata = {
title: 'Blog',
openGraph: {
title: 'Blog',
},
}
<!-- Output -->
<title>Blog</title>
<meta property="og:title" content="Blog" />
app/layout.js
의 title
은 app/blog/page.js
의 title
로 대체된다.app/layout.js
의 모든 openGraph
필드는 app/blog/page.js
에서 openGraph 메타데이터를 설정하므로 대체된다. openGraph.description
이 없는 점에 유의하자.일부 중첩 필드를 세그먼트 간에 공유하려면 변수를 사용하면 된다.
<!-- app/shared-metadata.js -->
export const openGraphImage = { images: ['http://...'] }
<!-- app/about/page.js -->
import { openGraphImage } from './shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'About',
},
}
중첩되지 않은 필드는 상속된다.
<!-- app/layout.js -->
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
}
<!-- app/about/page.js -->
export const metadata = {
title: 'About',
}
<!-- Output -->
<title>About</title>
<meta property="og:title" content="Acme" />
<meta property="og:description" content="Acme is a..." />