Menu

メタデータ

Next.js には、SEO と Web 共有性を向上させるために、アプリケーションのメタデータ(HTML の head 要素内の metalink タグなど)を定義できるメタデータ API があります。

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

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

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

静的メタデータ

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

layout.tsx
TypeScript
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: '...',
  description: '...',
}
 
export default function Page() {}

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

動的メタデータ

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

app/products/[id]/page.tsx
TypeScript
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 は、generateMetadata 内のデータ取得が完了するまで待機してから、クライアントに UI をストリーミングします。これにより、ストリーミングされたレスポンスの最初の部分に <head> タグが含まれることが保証されます。

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

メタデータ用の特殊なファイルは以下の通りです:

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

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

動作

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

デフォルトフィールド

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

  • meta charset タグは、Web サイトの文字エンコーディングを設定します。
  • meta viewport タグは、異なるデバイスに合わせて Web サイトのビューポート幅とスケールを設定します。
<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(ブログページ)

マージ

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

これは、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.jstitleapp/blog/page.jstitle置き換えられます
  • app/blog/page.jsopenGraph メタデータを設定しているため、app/layout.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',
}
 
// 出力:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />

メモ

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

動的画像生成

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

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

補足:

  • 例は Vercel OG Playground で利用可能です。
  • ImageResponse@vercel/ogSatori、Resvgを使用して、HTMLとCSSをPNGに変換します。
  • Edge Runtimeのみがサポートされています。デフォルトのNode.jsランタイムは動作しません。
  • フレックスボックスと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
TypeScript
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のリッチ結果テストまたは汎用のスキーママークアップバリデーターで検証およびテストできます。

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