Next.js에는 SEO 및 웹 공유성을 향상시키기 위해 애플리케이션의 메타데이터(예: HTML head
요소 내부의 meta
및 link
태그)를 정의할 수 있는 Metadata API가 있다.
애플리케이션에 메타데이터를 추가하는 두 가지 방법이 있다.
구성 기반 메타데이터
layout.js
또는 page.js
파일에서 정적 메타데이터 객체나 동적 generateMetadata
함수를 내보낸다.
파일 기반 메타데이터
라우트 세그먼트에 정적 또는 동적으로 생성된 특수 파일을 추가한다.
이러한 두 가지 옵션 모두 Next.js가 페이지에 대한 관련 <head>
요소를 자동으로 생성한다.
또한 ImageResponse
생성자를 사용하여 동적 OG 이미지를 생성할 수도 있다.
정적 메타데이터를 정의하려면 layout.js
또는 정적 page.js
파일에서 Metadata
객체를 내보낸다.
// layout.tsx or page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: '...',
description: '...',
};
export default function Page() {}
동적 값을 필요로하는 메타데이터를 가져오기 위해 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(`https://.../${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
를 통한)는 Server Components
에서만 지원된다.
라우트를 렌더링할 때, Next.js는 generateMetadata
, generateStaticParams
, layout
, page
및 Server Components
전체에서 동일한 데이터에 대한 중복된 fetch
요청을 자동으로 제거한다. fetch
를 사용할 수 없는 경우 React 캐시를 사용할 수 있다.
Next.js는 generateMetadata
내부에서 데이터를 가져오는 것이 완료될 때까지 UI를 클라이언트로 스트리밍하기 전까지 대기한다. 이는 스트리밍 응답의 첫 부분에 <head>
태그가 포함되도록 보장한다.
이러한 특수 파일들은 메타데이터로 사용할 수 있다.
favicon.ico, apple-icon.jpg
, 그리고 icon.jpg
opengraph-image.jpg
와 twitter-image.jpg
robots.txt
sitemap.xml
이러한 파일들은 정적 메타데이터로 사용하거나 코드로 프로그래밍적으로 생성할 수 있다.
파일 기반 메타데이터는 더 높은 우선순위를 가지며, 구성 기반 메타데이터보다 우선하여 적용된다.
경로에서 메타데이터를 정의하지 않더라도 항상 추가되는 두 가지 기본 메타 태그가 있다.
meta charset
태그는 웹 사이트의 문자 인코딩을 설정한다.
meta viewport
태그는 다른 기기에 맞게 웹 사이트의 뷰포트 너비와 확대/축소를 설정한다.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
디폴트 viewport
메타 태그를 덮어쓸 수 있다.
메타데이터는 순서대로 평가되며, 최종 페이지.js 세그먼트에 가장 가까운 세그먼트에서부터 시작하여 루트 세그먼트까지 내려간다. 예를 들면 다음과 같다.
app/layout.tsx
(루트 레이아웃)
app/blog/layout.tsx
(중첩된 블로그 레이아웃)
app/blog/[slug]/page.tsx
(블로그 페이지)
평가 순서를 따라 동일한 경로의 여러 세그먼트에서 내보낸 메타데이터 객체는 얕은 병합을 통해 경로의 최종 메타데이터 출력을 형성하기 위해 함께 병합된다. 중복된 키는 순서에 따라 교체된다.
이는 이전 세그먼트에서 정의된 openGraph
및 robots
와 같은 중첩 필드를 가진 메타데이터가 마지막 세그먼트에 의해 덮어씌워진다는 것을 의미한다.
// app/layout.ts
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/blog/page.js
에서 openGraph
메타데이터를 설정하기 때문에 app/layout.js
의 모든 openGraph
필드가 대체된다. openGraph.description
이 없는 것에 주목해야한다.
일부 중첩된 필드를 세그먼트 간에 공유하면서 다른 필드를 덮어쓰고 싶다면 별도의 변수로 분리할 수 있다.
// app/shared-metadata.js
export const openGraphImage = { images: ['http://...'] };
// app/page.js
import { openGraphImage } from './shared-metadata';
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Home',
},
};
// app/about/page.js
import { openGraphImage } from '../shared-metadata';
export const metadata = {
openGraph: {
...openGraphImage,
title: 'About',
},
};
위의 예시에서는 app/layout.js
와 app/about/page.js
간에 OG 이미지가 공유되고 제목은 다르다.
// app/layout.ts
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..." />
app/layout.js
의 title
은 app/about/page.js
의 title
에 의해 대체된다.
app/about/page.js
에서 openGraph
메타데이터를 설정하지 않았기 때문에 app/layout.js
의 모든 openGraph
필드가 상속된다.
ImageResponse
생성자를 사용하면 JSX와 CSS를 사용하여 동적 이미지를 생성할 수 있다. 이는 오픈 그래프 이미지, Twitter 카드 등의 소셜 미디어 이미지를 생성하는 데 유용하다.
ImageResponse
는 Edge Runtime을 사용하며, Next.js는 자동으로 캐시된 이미지에 올바른 헤더를 추가하여 성능을 향상시키고 다시 계산을 줄이는 데 도움을 준다.
사용하려면 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,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
}}
>
Hello world!
</div>
),
{
width: 1200,
height: 600,
},
);
}
ImageResponse
는 Route Handlers 및 파일 기반 메타데이터를 포함한 다른 Next.js API와 잘 통합된다. 예를 들어, opengraph-image.tsx
파일에서 ImageResponse
를 사용하여 빌드 시간에 또는 요청 시간에 동적으로 오픈 그래프 이미지를 생성할 수 있다.
ImageResponse
는 flexbox와 절대 위치 지정을 포함한 일반적인 CSS 속성, 사용자 정의 폰트, 텍스트 줄 바꿈, 가운데 정렬 및 중첩 이미지를 지원한다.
ImageResponse
는 HTML과 CSS를 PNG로 변환하기 위해 @vercel/og, Satori 및 Resvg를 사용한다.
Edge Runtime만 지원된다. 기본 Node.js 런타임은 작동하지 않는다.
flexbox와 CSS 속성의 일부만 지원된다. 고급 레이아웃(예: display: grid
)은 작동하지 않는다.
최대 번들 크기는 500KB
다. 번들 크기에는 JSX, CSS, 폰트, 이미지 및 기타 에셋이 포함된다. 제한을 초과하는 경우 에셋의 크기를 줄이거나 런타임에서 가져오는 방식을 고려해야 한다.
ttf
, otf
및 woff
폰트 형식만 지원된다. 폰트 구문 분석 속도를 극대화하기 위해 woff
보다는 ttf
또는 otf
가 선호된다.
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.image,
description: product.description,
};
return (
<section>
{/* Add JSON-LD to your page */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
);
}
Google의 Rich Results Test 또는 일반적인 Schema Markup Validator를 사용하여 구조화된 데이터를 유효성 검사하고 테스트할 수 있다.
schema-dts
와 같은 커뮤니티 패키지를 사용하여 TypeScript로 JSON-LD를 작성할 수 있다.
[ 출처 ]
https://nextjs.org/docs/app/building-your-application/optimizing/metadata