Next.js 메타데이터

Yun·2024년 8월 24일
0

개인공부

목록 보기
26/28

Metadata

메타데이터는 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

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.jstitleapp/blog/page.jstitle로 대체된다.
  • 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..." />

참고

0개의 댓글