メインコンテンツまでスキップ

メタデータ

Next.js には メタデータ API があり、アプリケーションのメタデータ(HTML head要素内のmetaタグやlinkタグなど)を定義して、SEOやウェブ共有性を向上させることができます。

アプリケーションにメタデータを追加する方法は2つあります:

  • 設定ベースメタデータ: 静的なメタデータオブジェクトまたは動的な generateMetadata 関数layout.js または page.js ファイルにエクスポートします。
  • ファイルベースのメタデータ: ルートセグメントに静的または動的に生成された特殊ファイルを追加します。

これらのオプションを使用すると、Next.js はページの関連する <head> 要素を自動的に生成します。 また、ImageResponse コンストラクタを使って動的な OG 画像を作成することもできます。

静的メタデータ

静的メタデータを定義するには、layout.js または 静的な page.js ファイルから メタデータオブジェクトをエクスポートします。

layout.tsx | page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
title: '...',
description: '...',
}

export default function Page() {}

利用可能なすべてのオプションについては、API リファレンスを参照してください。

動的メタデータ

generateMetadata 関数を使用すると、動的な値を必要とするメタデータを fetch できます。

app/products/[id]/page.tsx
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> {
// 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) {}

利用可能なすべてのパラメータについては、API リファレンスを参照してください。

Good to know:

  • generateMetadata による静的および動的メタデータは、Server Components でのみ サポートされます。
  • fetch リクエストは、generateMetadatagenerateStaticParams、Layouts、Pages、および Server Components 全体で同じデータに対して自動的にメモされます。fetch が利用できない場合は、React キャッシュを使用できます。
  • Next.js は、generateMetadata 内のデータ取得が完了するまで待ってから、UIをクライアントにストリーミングします。これにより、ストリームされたレスポンスの最初の部分に <head> タグが含まれることが保証されます。

ファイルベースのメタデータ

これらの特別なファイルはメタデータに利用することができます:

これらのファイルは静的なメタデータとして使用することもでき、コードを使ってプログラムで生成することもできます。

実装と例については、メタデータファイル API リファレンス と 動的な画像生成 を参照してください。

Behavior

ファイルベースのメタデータの方が優先順位が高く、設定ベースのメタデータよりも優先されます。

デフォルトフィールド

ルートがメタデータを定義していない場合でも、常に追加されるデフォルトの meta タグが 2 つあります:

  • meta charset タグは、ウェブサイトの文字エンコーディングを設定します。
  • meta viewport タグは、ウェブサイトのビューポート幅とスケールを設定し、異なるデバイス用に調整します。
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

Good to know: デフォルトの viewport meta タグを上書きすることができます。

順序

メタデータは、ルートセグメントから最後の page.js セグメントに最も近いセグメントまで、順番に評価されます。例えば以下の通りです。

  1. app/layout.tsx (ルートレイアウト)
  2. app/blog/layout.tsx (ネストされたブログレイアウト)
  3. app/blog/[slug]/page.tsx (ブログページ)

マージ

評価順序に従って、同じルート内の複数のセグメントからエクスポートされたメタデータオブジェクトが 浅く マージされ、ルートの最終的なメタデータ出力が形成されます。重複するキーは、その順序に基づいて 置き換えられます

つまり、以前のセグメントで定義された openGraphrobots のようなネストしたフィールドを持つメタデータは、それらを定義した最後のセグメントによって 上書き されます。

フィールドの上書き

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.jstitle は、app/blog/page.jstitle置き換えられます
  • app/layout.jsopenGraph フィールドはすべて app/blog/page.js置き換えられます。なぜなら、app/blog/page.jsopenGraph メタデータを設定するためです。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',
},
}

上の例では、OG 画像は app/layout.jsapp/about/page.js で共有されているが、タイトルは異なっています。

フィールドの継承

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..." />

  • app/layout.jstitle は、app/about/page.jstitle置き換えられます
  • app/about/page.jsopenGraph メタデータを設定しないため、app/layout.jsopenGraph フィールドはすべて app/about/page.js継承されます

動的な画像生成

ImageResponse コンストラクタを使用すると、JSX と CSS を使用して動的な画像を生成できます。 これは、Open Graph 画像や Twitter カードなどのソーシャルメディア画像を作成する際に便利です。

ImageResponseEdge Runtime を使用しており、Next.js はエッジでキャッシュされた画像に正しいヘッダーを自動的に追加するため、パフォーマンスの向上と再計算の削減に役立ちます。

これを使用するには、next/og から ImageResponse をインポートします:

app/about/route.js
import { ImageResponse } from 'next/og'

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 を使用すると、ビルド時にOpen Graph画像を生成したり、リクエスト時に動的に生成したりできます。

ImageResponse は、フレックスボックスや絶対配置、カスタムフォント、テキストラッピング、センタリング、ネストされた画像など、一般的なCSSプロパティをサポートしています。サポートされているCSSプロパティの完全なリストを参照してください。

Good to know:

  • Vercel OG Playgroundに例があります。
  • ImageResponse@vercel/ogSatori、Resvg を使ってHTMLとCSSをPNGに変換します。
  • Edge Runtime のみがサポートされています。デフォルトのNode.js Runtime は動作しません。
  • フレックスボックスとCSSプロパティのサブセットのみがサポートされています。高度なレイアウト(display: gridなど)は動作しません。
  • 最大バンドルサイズは 500KB です。バンドルサイズには、JSX、CSS、フォント、画像、その他のアセットが含まれます。制限を超える場合は、アセットのサイズを小さくするか、実行時に取得することを検討してください。
  • ttfotfwoff フォント形式のみに対応しています。フォントの解析速度を最大にするため、woff よりも ttf または otf が優先されます。

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.image,
description: product.description,
}

return (
<section>
{/* Add JSON-LD to your page */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
)
}

Google のリッチリザルトテストや一般的な Schema Markup Validator で構造化データを検証し、テストすることができます。

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.',
}