Next.js에는 향상된 SEO 및 웹 공유 가능성을 위해 애플리케이션 메타데이터(예: HTML 헤드 요소 내의 메타 및 링크 태그)를 정의하는 데 사용할 수 있는 메타데이터 API가 있다. 애플리케이션에 메타데이터를 추가할 수 있는 두 가지 방법이 있다.
Config-based Metadata | layout.js 또는 pages.js 파일에서 정적 메타데이터 개체 또는 동적 generateMetadata 함수를 내보낸다. |
File-based Metadata | 경로 세그먼트에 정적 또는 동적으로 생성된 특수 파일을 추가한다. |
이 두 가지 옵션을 모두 사용하면 Next.js가 페이지에 대한 관련 <head> 요소를 자동으로 생성한다. ImageResponse 생성자를 사용하여 동적 OG 이미지를 생성할 수도 있다.
- Static Metadata
정적 메타데이터를 정의하려면 layout.js 또는 정적 page.js 파일에서 Metadata 개체를 내보낸다.
// layout.tsx / page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: '...',
description: '...',
}
export default function Page() {}
- Dynamic Metadata
generateMetadata 함수를 사용하여 동적 값이 필요한 메타데이터를 가져올 수 있다.
// app/products/[id]/page.tsx
import { 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> {
// read route params
const id = params.id
// fetch data
const product = await fetch(`htttps://.../${id}`).then((res) => res.json())
// optionally access and extend (rather than replace) parent metadata
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) {}
generateMetadata를 통한 정적 및 동적 메타데이터는 모두 서버 컴포넌트에서만 지원된다. 그리고 경로를 렌더링 할 때 Next.js generateMetadata, generateStaticParams, Layouts, Pages 및 서버 컴포넌트에서 동일한 데이터에 대한 가져오기 요청을 자동으로 중복 제거한다. 가져오기를 사용할 수 없는 경우 React 캐시를 사용할 수 있다.
Next.js는 UI를 클라이언트로 스트리밍 하기 전에 generateMetadata 내에서 데디터 가져오기가 완료될 때까지 기다린다. 이렇게 하면 스트리밍 응답의 첫 번째 부분에 <head> 태그가 포함된다.
- File-based metadata
다음 특수 파일은 메타데이터에 사용할 수 있다.
favicon.ico. apple-icon.jpg, and icon.jpg |
opengraph-image.jpg and twiiter-image.jpg |
robots.txt |
sitemap.xml |
정적 메타데이터에 대해 이를 사용하거나 코드를 사용하여 프로그래밍 방식으로 이러한 파일을 생성할 수 있다.
- Behavior
파일 기반 메타데이터는 우선순위가 더 높으며 모든 구성 기반 메타데이터를 재정의한다.
- Default Fields
경로가 메타데이터를 정의하지 않는 경우에도 항상 추가되는 두 가지 기본 메타 태그가 있다. 첫째로 메타 문자셋 태그는 웹사이트의 문자 인코딩을 설정한다. 둘째로 메타 뷰포트 태그는 웹사이트의 뷰포트 너비와 배율을 설정하여 다양한 장치에 맞게 조정한다.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
- Ordering
메타데이터는 루트 세그먼트에서 시작하여 마지막 page.js 세그먼트에 가장 가까운 세그먼트까지 순서대로 평가된다. 예를 들면,
- app/layout.tsx (Root Layout)
- app/blog/layout.tsx (Nested Blog Layout)
- app/blog/[slug]/page.tsx (Blog Page)
- Merging
평가 순서에 따라 동일한 경로의 여러 세그먼트에서 내보낸 메타데이터 개체는 얕게 병합되어 경로의 최종 메타데이터 출력을 형성한다. 중복 키는 순서에 따라 대체된다.
즉, 이전 세그먼트에서 정의된 openGraph 및 로봇과 같은 중첩 필드가 있는 메타데이터는 이를 정의하기 위해 마지막 세그먼트로 덮어쓴다.
- Overwriting fields
// app/layout.js
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme if 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의 제목은 app/blog/page.js의 제목으로 대체된다. app/blog/page.js가 openGraph 메타데이터를 설정하기 때문에 app/layout.js의 모든 openGraph 필드는 app/blog/page.js로 대체된다. openGraph.description이 없다는 점에 유의하면 된다.
세그먼트 간에 일부 중첩된 필드를 공유하면서 다른 필드를 덮어쓰려는 경우 별도의 변수로 가져올 수 있다.
// app/shared-metadata.js
export const openGraphImage = { images: ['https://...'] }
// app/page.js
import { openGraphImage } from './shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Home',
},
}
- Inheriting fields
// app/layout.js
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
dscription: '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..." />
app/layout.js의 제목은 app/about/page.js의 제목으로 대체된다. app/layout.js의 모든 openGraph 필드는 app/about/page.js가 openGraph 메타데이터를 설정하지 않기 때문에 app/about/page.js에서 상속된다.
- Dynamic Image Generation
ImageResponse 생성자를 사용하면 JSX 및 CSS를 사용하여 동적 이미지를 생성할 수 있다. Open Graph 이미지, Twitter 카드 등과 같은 소셜 미디어 이미지를 만드는 데 유용하다.
ImageResponse는 Edge Runtime을 사용하고 Next.js는 Edge에서 캐시 된 이미지에 올바른 헤더를 자동으로 추가하여 성능을 개선하고 재계산을 줄이는 데 도움을 준다.
이를 사용하려면 next/server에서 ImageResponse를 가져오면 된다.
// app/about/route.jsx
import { ImageResponse } from 'next/server'
export const runtime = 'edge'
export async function GET() {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
bacground: 'white',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
}}
>
Hello world!
</div>
)
{
width: 1200,
height: 600,
}
)
}
ImageResponse는 경로 처리기 및 파일 기반 메타데이터를 포함하여 다른 Next.js API와 잘 통합된다. 예를 들어 opengraph-image.tsx 파일에서 ImageResponse를 사용하여 빌드 시 또는 요청 시 동적으로 오픈 그래프 이미지를 생성할 수 있다.
ImageResponse는 flexbox 및 절대 위치 지정, 사용자 지정 글꼴, 텍스트 줄 바꿈 가운데 맞춤 및 중첩 이미지를 비롯한 일반적인 CSS 속성을 지원한다.
- JSON-LD
JSON-LD는 콘텐츠를 이해하기 위해 검색 엔진에서 사용할 수 있는 구조화된 데이터 양식이다. 예를 들어 사람, 이벤트, 조직, 영화, 책, 조리법 및 기타 여러 유형의 엔터티를 설명하는 데 사용할 수 있다.
JSON-LD에 대한 현재 권장 사항은 구조화된 데이터를 layout.js 또는 page.js 컴포넌트에서 <script> 태그로 렌더링 하는 것이다.
// app/products/[id]/page.tsx
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.iamge,
description: product.description,
}
return (
<section>
{/* Add JSON-LD to your page */}
<script
type="application/Id+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLD) }}
/>
{/* ... */}
</section>
)
}
Google용 리치 결과 테스트 또는 일반 스키마 마크업 검사기로 구조화된 데이터의 유효성을 검사하고 테스트할 수 있다. schema-dts와 같은 커뮤니티 패키지를 사용하여 TypeScript로 JSON-LD를 입력할 수 있다.
import { Product, WithContext } from 'schema-dts';
const jsonLd: WithContext<Product> = {
'@context': 'https://schema.org',
'@type': 'Product',
name: 'Next.js Sticker',
image: 'https://nextjs.org/imgs/sticker.png',
description: 'Dynamic at the speed of static',
}
'Next.js' 카테고리의 다른 글
Next.js 9-7 Lazy Loading (0) | 2023.06.15 |
---|---|
Next.js 9-6 Static Assets (0) | 2023.06.14 |
Next.js 9-4 Script Optimization (0) | 2023.06.09 |
Next.js 9-3 Font Optimization (0) | 2023.06.08 |
Next.js 11-13 Routing Internationalization (1) | 2023.06.08 |