概要
Next.js App Router では metadata オブジェクトを export するだけで <title> / <meta> タグが自動生成される。
動的ルート(/posts/[slug] 等)ではパラメータに応じたメタデータを generateMetadata で生成する。
インストール
# 追加インストールは不要
静的ページの metadata
// src/app/about/page.tsx
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "About | TOOLS BOX",
description: "このサイトについての説明ページです。",
openGraph: {
title: "About | TOOLS BOX",
description: "このサイトについての説明ページです。",
url: "https://example.com/about",
siteName: "TOOLS BOX",
images: [{ url: "https://example.com/og-image.png", width: 1200, height: 630 }],
type: "website",
},
};
export default function AboutPage() {
return <main><h1>About</h1></main>;
}
layout.tsx で共通メタデータを定義する
// src/app/layout.tsx
import type { Metadata } from "next";
export const metadata: Metadata = {
title: {
default: "TOOLS BOX",
template: "%s | TOOLS BOX", // page.tsx の title が "%s" に入る
},
description: "Next.js / React / TypeScript のコードサンプル集。",
};
動的ルートの generateMetadata
// src/app/posts/[slug]/page.tsx
import type { Metadata } from "next";
type Props = { params: Promise<{ slug: string }> };
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
// 実際の実装では DB や CMS からデータを取得する
const post = await fetchPost(slug);
return {
title: post.title, // layout.tsx の template で "%s | TOOLS BOX" になる
description: post.description,
openGraph: {
title: post.title,
description: post.description,
images: [{ url: post.ogImage }],
},
};
}
async function fetchPost(slug: string) {
return { title: `Post: ${slug}`, description: "記事の説明", ogImage: "/og.png" };
}
export default async function PostPage({ params }: Props) {
const { slug } = await params;
return <main><h1>{slug}</h1></main>;
}
ポイント
layout.tsxにtitle.templateを設定すると、配下のpage.tsxが文字列でtitleを返すだけで"ページ名 | サイト名"の形式になるgenerateMetadataはサーバーサイドで実行されるため、DB や API からのデータ取得が可能openGraph.imagesには絶対 URL を指定する(相対パス不可)page.tsxのmetadataは同階層のlayout.tsxの値を上書きする