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

Metadata

Next.jsには、アプリケーションのメタデータ(例: HTMLのhead要素内のmetaタグやlinkタグ)を定義するためのMetadata APIがあります。これにより、SEOやWebの共有性が向上します。

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

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

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

静的メタデータ

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

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

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

export default function Page() {}

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

動的メタデータ

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

app/products/[id]/page.tsx
import type { Metadata, ResolvingMetadata } from 'next'

type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}

export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// ルートパラメータを読み取る
const id = (await params).id

// データをフェッチする
const product = await fetch(`https://.../${id}`).then((res) => res.json())

// 親メタデータにアクセスして拡張する(置換しない)ことができます
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リファレンスを参照してください。

知っておくと良いこと:

  • generateMetadataによる静的および動的メタデータは、サーバーコンポーネントでのみサポートされています
  • fetchリクエストは、generateMetadatagenerateStaticParams、レイアウト、ページ、およびサーバーコンポーネント間で同じデータのために自動的にメモ化されます。fetchが利用できない場合は、Reactのcacheを使用できます。
  • Next.jsは、クライアントにUIをストリーミングする前にgenerateMetadata内でのデータフェッチが完了するまで待ちます。これにより、ストリーミングされたレスポンスの最初の部分が<head>タグを含むことが保証されます。

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

メタデータに使用できる特別なファイルが利用可能です:

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

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

動作

ファイルベースのメタデータは優先度が高く、設定ベースのメタデータを上書きします。

デフォルトフィールド

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

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

知っておくと良いこと: デフォルトのviewportメタタグを上書きすることができます。

順序

メタデータは、root セグメントから最終的なpage.jsセグメントに最も近いセグメントまで順番に評価されます。例えば:

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

マージ

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

つまり、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',
},
}

// 出力:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />

上記の例では:

  • app/layout.jstitleは、app/blog/page.jstitle置換されます。
  • app/blog/page.jsopenGraphメタデータを設定しているため、app/layout.jsのすべてのopenGraphフィールドがapp/blog/page.js置換されます。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',
}

// 出力:
// <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.jsのすべてのopenGraphフィールドがapp/about/page.js継承されます。

動的画像生成

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

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

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

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は、他のNext.js APIとよく統合されており、例としてRoute Handlersおよびファイルベースのメタデータが含まれます。例えば、ImageResponseopengraph-image.tsxファイル内で使用して、ビルド時またはリクエスト時にOpen Graph画像を動的に生成することができます。

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

知っておくと良いこと:

  • Vercel OG Playgroundに例があります。
  • ImageResponseは、HTMLとCSSをPNGに変換するために@vercel/ogSatori、およびResvgを使用します。
  • Edge Runtimeのみサポートされています。デフォルトのNode.jsランタイムは機能しません。
  • フレックスボックスと一部のCSSプロパティのみサポートされています。高度なレイアウト(例:display: grid)は機能しません。
  • 最大バンドルサイズは500KBです。バンドルサイズには、JSX、CSS、フォント、画像、その他のアセットが含まれます。限度を超えた場合は、アセットのサイズを減らすか、実行時にフェッチすることを検討してください。
  • ttfotf、およびwoffフォント形式のみサポートされています。フォントの解析速度を最大化するために、ttfまたはotfwoffよりも好まれます。

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>
{/* ページにJSON-LDを追加 */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
)
}

構造化データをリッチリザルトテスト(Google用)または汎用スキーママークアップバリデーターで検証およびテストできます。

TypeScriptを使用して、コミュニティパッケージ(例:schema-dts)を使用して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.',
}