コンテンツへスキップ

メタデータ

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

アプリケーションにメタデータを追加する方法は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> {
  // read route params
  const { id } = await params
 
  // 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リファレンスを参照してください。

知っておくと良いこと:

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

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

以下の特殊ファイルがメタデータとして利用可能です。

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

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

挙動

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

デフォルトフィールド

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

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

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

順序

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

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

マージ

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

これは、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.jsのすべてのopenGraphフィールドは、app/blog/page.jsopenGraphメタデータを設定しているため、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',
}
 
// 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/layout.jsのすべてのopenGraphフィールドは、app/about/page.jsopenGraphメタデータを設定していないため、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とよく統合されています。例えば、opengraph-image.tsxファイルでImageResponseを使用して、ビルド時またはリクエスト時に動的にOpen Graph画像を生成できます。

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

知っておくと良いこと:

  • 例はVercel OG Playgroundで利用可能です。
  • ImageResponseは、HTMLとCSSをPNGに変換するために@vercel/ogSatori、およびResvgを使用します。
  • flexboxと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 { id } = await params
  const product = await getProduct(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のリッチリザルトテスト、または汎用のスキーママークアップバリデータで検証・テストできます。

JSON-LDをTypeScriptで型付けするには、schema-dtsのようなコミュニティパッケージを使用できます。

import { Product, WithContext } from 'schema-dts'
 
const jsonLd: WithContext<Product> = {
  '@context': 'https://schema.org',
  '@type': 'Product',
  name: 'Next.js Sticker',
  image: 'https://nextjs.dokyumento.jp/imgs/sticker.png',
  description: 'Dynamic at the speed of static.',
}