Next.js App Router의 Metadata API
Next.js 13.4+의 App Router는 Metadata API를 통해 SEO 메타태그를 선언적으로 관리합니다.
정적 메타데이터
import type { Metadata } from 'next';
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: {
default: '내 블로그',
template: '%s | 내 블로그'
},
description: '시니어 개발자의 기술 블로그',
keywords: ['개발', '프로그래밍', '기술블로그'],
openGraph: {
type: 'website',
locale: 'ko_KR',
url: 'https://example.com',
siteName: '내 블로그',
images: [{ url: '/og-image.png', width: 1200, height: 630 }]
},
twitter: { card: 'summary_large_image', creator: '@myhandle' },
robots: {
index: true, follow: true,
googleBot: { index: true, follow: true, 'max-image-preview': 'large' }
},
verification: { google: 'google-code', naver: 'naver-code' }
};
동적 메타데이터
interface Props { params: { slug: string }; }
export async function generateMetadata({ params }: Props): Promise {
const post = await getPost(params.slug);
if (!post) return { title: '게시글을 찾을 수 없습니다' };
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
type: 'article',
publishedTime: post.createdAt.toISOString(),
authors: [post.author.name],
images: [{ url: post.thumbnail || '/og-default.png', width: 1200, height: 630 }]
}
};
}
JSON-LD 구조화 데이터
export function ArticleJsonLd(props: {
title: string; description: string; url: string;
imageUrl: string; datePublished: string; authorName: string;
}) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: props.title,
description: props.description,
url: props.url,
image: props.imageUrl,
datePublished: props.datePublished,
author: { '@type': 'Person', name: props.authorName },
publisher: {
'@type': 'Organization', name: '내 블로그',
logo: { '@type': 'ImageObject', url: 'https://example.com/logo.png' }
}
};
return (
댓글 0