跳到主要內容
API 參考函式generateMetadata

generateMetadata

此頁面涵蓋所有使用 generateMetadata 和靜態 metadata 物件的基於配置的 Metadata 選項。

layout.tsx | page.tsx
import type { Metadata } from 'next'
 
// either Static metadata
export const metadata: Metadata = {
  title: '...',
}
 
// or Dynamic metadata
export async function generateMetadata({ params }) {
  return {
    title: '...',
  }
}

要知道:

  • metadata 物件和 generateMetadata 函式匯出僅在伺服器元件中支援
  • 您無法從同一個路由區段同時匯出 metadata 物件和 generateMetadata 函式。

metadata 物件

若要定義靜態 metadata,請從 layout.jspage.js 檔案匯出 Metadata 物件

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

請參閱 Metadata 欄位 以取得完整支援選項列表。

generateMetadata 函式

動態 metadata 取決於動態資訊,例如目前的路由參數、外部資料,或父區段中的 metadata,可以透過匯出傳回 Metadata 物件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).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) {}

參數

generateMetadata 函式接受以下參數

  • props - 一個物件,包含目前路由的參數

    • params - 一個物件,包含從根區段到呼叫 generateMetadata 的區段的動態路由參數物件。 範例

      路由網址params
      app/shop/[slug]/page.js/shop/1{ slug: '1' }
      app/shop/[tag]/[item]/page.js/shop/1/2{ tag: '1', item: '2' }
      app/shop/[...slug]/page.js/shop/1/2{ slug: ['1', '2'] }
    • searchParams - 一個物件,包含目前網址的 搜尋參數。 範例

      網址searchParams
      /shop?a=1{ a: '1' }
      /shop?a=1&b=2{ a: '1', b: '2' }
      /shop?a=1&a=2{ a: ['1', '2'] }
  • parent - 從父路由區段解析的 metadata 的 Promise。

回傳值

generateMetadata 應傳回包含一或多個 metadata 欄位的 Metadata 物件

要知道:

  • 如果 metadata 不依賴執行階段資訊,則應使用靜態 metadata 物件 而非 generateMetadata 來定義。
  • fetch 請求會在 generateMetadatagenerateStaticParams、版面配置、頁面和伺服器元件之間,針對相同資料自動進行記憶化。如果 fetch 無法使用,則可以使用 React cache
  • searchParams 僅在 page.js 區段中可用。
  • Next.js 的 redirect()notFound() 方法也可以在 generateMetadata 內部使用。

Metadata 欄位

title

title 屬性用於設定文件的標題。它可以定義為簡單的字串或選用的樣板物件

字串

layout.js | page.js
export const metadata = {
  title: 'Next.js',
}
<head> 輸出
<title>Next.js</title>

樣板物件

app/layout.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: {
    template: '...',
    default: '...',
    absolute: '...',
  },
}
預設值

title.default 可用於為未定義 title 的子路由區段提供fallback 標題

app/layout.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: {
    default: 'Acme',
  },
}
app/about/page.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {}
 
// Output: <title>Acme</title>
樣板

title.template 可用於為路由區段中定義的 titles 新增前綴或後綴。

app/layout.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
    default: 'Acme', // a default is required when creating a template
  },
}
app/about/page.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'About',
}
 
// Output: <title>About | Acme</title>

要知道:

  • title.template 適用於路由區段,不適用於定義它的區段。 這表示

    • 當您新增 title.template 時,必須要有 title.default
    • layout.js 中定義的 title.template 不會套用至在相同路由區段的 page.js 中定義的 title
    • page.js 中定義的 title.template 沒有任何作用,因為頁面永遠是終止區段(它沒有任何子路由區段)。
  • 如果路由未定義 titletitle.default,則 title.template 沒有任何作用

絕對

title.absolute 可用於提供忽略父區段中設定的 title.template 的標題。

app/layout.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: {
    template: '%s | Acme',
  },
}
app/about/page.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: {
    absolute: 'About',
  },
}
 
// Output: <title>About</title>

要知道:

  • layout.js

    • title (字串) 和 title.default 定義子區段的預設標題(未定義自己的 title)。如果存在,它將擴充來自最近父區段的 title.template
    • title.absolute 定義子區段的預設標題。它會忽略來自父區段的 title.template
    • title.template 為子區段定義新的標題樣板。
  • page.js

    • 如果頁面未定義自己的標題,將會使用最近父項解析的標題。
    • title (字串) 定義路由標題。如果存在,它將擴充來自最近父區段的 title.template
    • title.absolute 定義路由標題。它會忽略來自父區段的 title.template
    • title.templatepage.js 中沒有任何作用,因為頁面永遠是路由的終止區段。

description

layout.js | page.js
export const metadata = {
  description: 'The React Framework for the Web',
}
<head> 輸出
<meta name="description" content="The React Framework for the Web" />

基本欄位

layout.js | page.js
export const metadata = {
  generator: 'Next.js',
  applicationName: 'Next.js',
  referrer: 'origin-when-cross-origin',
  keywords: ['Next.js', 'React', 'JavaScript'],
  authors: [{ name: 'Seb' }, { name: 'Josh', url: 'https://nextjs.dev.org.tw' }],
  creator: 'Jiachi Liu',
  publisher: 'Sebastian Markbåge',
  formatDetection: {
    email: false,
    address: false,
    telephone: false,
  },
}
<head> 輸出
<meta name="application-name" content="Next.js" />
<meta name="author" content="Seb" />
<link rel="author" href="https://nextjs.dev.org.tw" />
<meta name="author" content="Josh" />
<meta name="generator" content="Next.js" />
<meta name="keywords" content="Next.js,React,JavaScript" />
<meta name="referrer" content="origin-when-cross-origin" />
<meta name="color-scheme" content="dark" />
<meta name="creator" content="Jiachi Liu" />
<meta name="publisher" content="Sebastian Markbåge" />
<meta name="format-detection" content="telephone=no, address=no, email=no" />

metadataBase

metadataBase 是一個方便的選項,可為需要完整限定網址的 metadata 欄位設定基本網址前綴。

  • metadataBase 允許在目前路由區段及其下方定義的基於網址的 metadata 欄位使用相對路徑,而不是原本需要的絕對網址。
  • 欄位的相對路徑將與 metadataBase 組合成完整的限定網址。
  • 如果未設定,metadataBase自動填入預設值
layout.js | page.js
export const metadata = {
  metadataBase: new URL('https://acme.com'),
  alternates: {
    canonical: '/',
    languages: {
      'en-US': '/en-US',
      'de-DE': '/de-DE',
    },
  },
  openGraph: {
    images: '/og-image.png',
  },
}
<head> 輸出
<link rel="canonical" href="https://acme.com" />
<link rel="alternate" hreflang="en-US" href="https://acme.com/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://acme.com/de-DE" />
<meta property="og:image" content="https://acme.com/og-image.png" />

要知道:

  • metadataBase 通常在根 app/layout.js 中設定,以套用至所有路由中基於網址的 metadata 欄位。
  • 所有需要絕對網址的基於網址的 metadata 欄位都可以使用 metadataBase 選項進行設定。
  • metadataBase 可以包含子網域,例如 https://app.acme.com 或基本路徑,例如 https://acme.com/start/from/here
  • 如果 metadata 欄位提供絕對網址,則會忽略 metadataBase
  • 在基於網址的 metadata 欄位中使用相對路徑而不設定 metadataBase 將會導致建置錯誤。
  • Next.js 會將 metadataBase (例如 https://acme.com/) 和相對欄位 (例如 /path) 之間的重複斜線正規化為單一斜線 (例如 https://acme.com/path)

預設值

如果未設定,metadataBase 具有預設值

在 Vercel 上

  • 對於生產環境部署,將使用 VERCEL_PROJECT_PRODUCTION_URL
  • 對於預覽部署,VERCEL_BRANCH_URL 將優先使用,如果不存在,則 fallback 至 VERCEL_URL

如果這些值存在,它們將用作 metadataBase預設值,否則 fallback 至 https://127.0.0.1:${process.env.PORT || 3000}。 這允許 Open Graph 圖片在本地建置和 Vercel 預覽和生產環境部署上都能運作。 當覆寫預設值時,我們建議使用環境變數來計算網址。 這允許為本機開發、預演和生產環境設定網址。

請參閱 系統環境變數 文件以取得更多詳細資訊。

URL 組成

URL 組成優先考慮開發人員的意圖,而不是預設的目錄遍歷語意。

  • metadataBasemetadata 欄位之間的尾部斜線會被正規化。
  • metadata 欄位中的「絕對」路徑(通常會取代整個網址路徑)被視為「相對」路徑(從 metadataBase 的末端開始)。

例如,給定以下 metadataBase

app/layout.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  metadataBase: new URL('https://acme.com'),
}

任何繼承上述 metadataBase 並設定自己值的 metadata 欄位都將解析如下

metadata 欄位已解析的網址
/https://acme.com
./https://acme.com
paymentshttps://acme.com/payments
/paymentshttps://acme.com/payments
./paymentshttps://acme.com/payments
../paymentshttps://acme.com/payments
https://beta.acme.com/paymentshttps://beta.acme.com/payments

openGraph

layout.js | page.js
export const metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    url: 'https://nextjs.dev.org.tw',
    siteName: 'Next.js',
    images: [
      {
        url: 'https://nextjs.dev.org.tw/og.png', // Must be an absolute URL
        width: 800,
        height: 600,
      },
      {
        url: 'https://nextjs.dev.org.tw/og-alt.png', // Must be an absolute URL
        width: 1800,
        height: 1600,
        alt: 'My custom alt',
      },
    ],
    videos: [
      {
        url: 'https://nextjs.dev.org.tw/video.mp4', // Must be an absolute URL
        width: 800,
        height: 600,
      },
    ],
    audio: [
      {
        url: 'https://nextjs.dev.org.tw/audio.mp3', // Must be an absolute URL
      },
    ],
    locale: 'en_US',
    type: 'website',
  },
}
<head> 輸出
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:url" content="https://nextjs.dev.org.tw/" />
<meta property="og:site_name" content="Next.js" />
<meta property="og:locale" content="en_US" />
<meta property="og:image" content="https://nextjs.dev.org.tw/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
<meta property="og:image" content="https://nextjs.dev.org.tw/og-alt.png" />
<meta property="og:image:width" content="1800" />
<meta property="og:image:height" content="1600" />
<meta property="og:image:alt" content="My custom alt" />
<meta property="og:video" content="https://nextjs.dev.org.tw/video.mp4" />
<meta property="og:video:width" content="800" />
<meta property="og:video:height" content="600" />
<meta property="og:audio" content="https://nextjs.dev.org.tw/audio.mp3" />
<meta property="og:type" content="website" />
layout.js | page.js
export const metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    type: 'article',
    publishedTime: '2023-01-01T00:00:00.000Z',
    authors: ['Seb', 'Josh'],
  },
}
<head> 輸出
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2023-01-01T00:00:00.000Z" />
<meta property="article:author" content="Seb" />
<meta property="article:author" content="Josh" />

要知道:

  • 對於 Open Graph 圖片,使用基於檔案的 Metadata API 可能更方便。 基於檔案的 API 會自動為您產生正確的 metadata,而不是必須將配置匯出與實際檔案同步。

robots

layout.tsx | page.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  robots: {
    index: true,
    follow: true,
    nocache: false,
    googleBot: {
      index: true,
      follow: true,
      noimageindex: false,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
}
<head> 輸出
<meta name="robots" content="index, follow" />
<meta
  name="googlebot"
  content="index, follow, max-video-preview:-1, max-image-preview:large, max-snippet:-1"
/>

icons

要知道:我們建議盡可能對圖示使用基於檔案的 Metadata API。 基於檔案的 API 會自動為您產生正確的 metadata,而不是必須將配置匯出與實際檔案同步。

layout.js | page.js
export const metadata = {
  icons: {
    icon: '/icon.png',
    shortcut: '/shortcut-icon.png',
    apple: '/apple-icon.png',
    other: {
      rel: 'apple-touch-icon-precomposed',
      url: '/apple-touch-icon-precomposed.png',
    },
  },
}
<head> 輸出
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
  rel="apple-touch-icon-precomposed"
  href="/apple-touch-icon-precomposed.png"
/>
layout.js | page.js
export const metadata = {
  icons: {
    icon: [
      { url: '/icon.png' },
      new URL('/icon.png', 'https://example.com'),
      { url: '/icon-dark.png', media: '(prefers-color-scheme: dark)' },
    ],
    shortcut: ['/shortcut-icon.png'],
    apple: [
      { url: '/apple-icon.png' },
      { url: '/apple-icon-x3.png', sizes: '180x180', type: 'image/png' },
    ],
    other: [
      {
        rel: 'apple-touch-icon-precomposed',
        url: '/apple-touch-icon-precomposed.png',
      },
    ],
  },
}
<head> 輸出
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="icon" href="https://example.com/icon.png" />
<link rel="icon" href="/icon-dark.png" media="(prefers-color-scheme: dark)" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
  rel="apple-touch-icon-precomposed"
  href="/apple-touch-icon-precomposed.png"
/>
<link
  rel="apple-touch-icon"
  href="/apple-icon-x3.png"
  sizes="180x180"
  type="image/png"
/>

要知道:Microsoft Edge 的 Chromium 建置版本不再支援 msapplication-* meta 標籤,因此不再需要。

themeColor

已棄用:Next.js 14 起,metadata 中的 themeColor 選項已棄用。 請改用viewport 設定

colorScheme

已棄用:Next.js 14 起,metadata 中的 colorScheme 選項已棄用。 請改用viewport 設定

manifest

Web 應用程式資訊清單,如 Web Application Manifest 規範 中所定義。

layout.js | page.js
export const metadata = {
  manifest: 'https://nextjs.dev.org.tw/manifest.json',
}
<head> 輸出
<link rel="manifest" href="https://nextjs.dev.org.tw/manifest.json" />

twitter

Twitter 規範(令人驚訝地)不僅用於 X(以前稱為 Twitter)。

深入瞭解 Twitter Card 標記參考

layout.js | page.js
export const metadata = {
  twitter: {
    card: 'summary_large_image',
    title: 'Next.js',
    description: 'The React Framework for the Web',
    siteId: '1467726470533754880',
    creator: '@nextjs',
    creatorId: '1467726470533754880',
    images: ['https://nextjs.dev.org.tw/og.png'], // Must be an absolute URL
  },
}
<head> 輸出
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:image" content="https://nextjs.dev.org.tw/og.png" />
layout.js | page.js
export const metadata = {
  twitter: {
    card: 'app',
    title: 'Next.js',
    description: 'The React Framework for the Web',
    siteId: '1467726470533754880',
    creator: '@nextjs',
    creatorId: '1467726470533754880',
    images: {
      url: 'https://nextjs.dev.org.tw/og.png',
      alt: 'Next.js Logo',
    },
    app: {
      name: 'twitter_app',
      id: {
        iphone: 'twitter_app://iphone',
        ipad: 'twitter_app://ipad',
        googleplay: 'twitter_app://googleplay',
      },
      url: {
        iphone: 'https://iphone_url',
        ipad: 'https://ipad_url',
      },
    },
  },
}
<head> 輸出
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:card" content="app" />
<meta name="twitter:image" content="https://nextjs.dev.org.tw/og.png" />
<meta name="twitter:image:alt" content="Next.js Logo" />
<meta name="twitter:app:name:iphone" content="twitter_app" />
<meta name="twitter:app:id:iphone" content="twitter_app://iphone" />
<meta name="twitter:app:id:ipad" content="twitter_app://ipad" />
<meta name="twitter:app:id:googleplay" content="twitter_app://googleplay" />
<meta name="twitter:app:url:iphone" content="https://iphone_url" />
<meta name="twitter:app:url:ipad" content="https://ipad_url" />
<meta name="twitter:app:name:ipad" content="twitter_app" />
<meta name="twitter:app:name:googleplay" content="twitter_app" />

viewport

已棄用:Next.js 14 起,metadata 中的 viewport 選項已棄用。 請改用viewport 設定

verification

layout.js | page.js
export const metadata = {
  verification: {
    google: 'google',
    yandex: 'yandex',
    yahoo: 'yahoo',
    other: {
      me: ['my-email', 'my-link'],
    },
  },
}
<head> 輸出
<meta name="google-site-verification" content="google" />
<meta name="y_key" content="yahoo" />
<meta name="yandex-verification" content="yandex" />
<meta name="me" content="my-email" />
<meta name="me" content="my-link" />

appleWebApp

layout.js | page.js
export const metadata = {
  itunes: {
    appId: 'myAppStoreID',
    appArgument: 'myAppArgument',
  },
  appleWebApp: {
    title: 'Apple Web App',
    statusBarStyle: 'black-translucent',
    startupImage: [
      '/assets/startup/apple-touch-startup-image-768x1004.png',
      {
        url: '/assets/startup/apple-touch-startup-image-1536x2008.png',
        media: '(device-width: 768px) and (device-height: 1024px)',
      },
    ],
  },
}
<head> 輸出
<meta
  name="apple-itunes-app"
  content="app-id=myAppStoreID, app-argument=myAppArgument"
/>
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Apple Web App" />
<link
  href="/assets/startup/apple-touch-startup-image-768x1004.png"
  rel="apple-touch-startup-image"
/>
<link
  href="/assets/startup/apple-touch-startup-image-1536x2008.png"
  media="(device-width: 768px) and (device-height: 1024px)"
  rel="apple-touch-startup-image"
/>
<meta
  name="apple-mobile-web-app-status-bar-style"
  content="black-translucent"
/>

alternates

layout.js | page.js
export const metadata = {
  alternates: {
    canonical: 'https://nextjs.dev.org.tw',
    languages: {
      'en-US': 'https://nextjs.dev.org.tw/en-US',
      'de-DE': 'https://nextjs.dev.org.tw/de-DE',
    },
    media: {
      'only screen and (max-width: 600px)': 'https://nextjs.dev.org.tw/mobile',
    },
    types: {
      'application/rss+xml': 'https://nextjs.dev.org.tw/rss',
    },
  },
}
<head> 輸出
<link rel="canonical" href="https://nextjs.dev.org.tw" />
<link rel="alternate" hreflang="en-US" href="https://nextjs.dev.org.tw/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://nextjs.dev.org.tw/de-DE" />
<link
  rel="alternate"
  media="only screen and (max-width: 600px)"
  href="https://nextjs.dev.org.tw/mobile"
/>
<link
  rel="alternate"
  type="application/rss+xml"
  href="https://nextjs.dev.org.tw/rss"
/>
layout.js | page.js
export const metadata = {
  appLinks: {
    ios: {
      url: 'https://nextjs.dev.org.tw/ios',
      app_store_id: 'app_store_id',
    },
    android: {
      package: 'com.example.android/package',
      app_name: 'app_name_android',
    },
    web: {
      url: 'https://nextjs.dev.org.tw/web',
      should_fallback: true,
    },
  },
}
<head> 輸出
<meta property="al:ios:url" content="https://nextjs.dev.org.tw/ios" />
<meta property="al:ios:app_store_id" content="app_store_id" />
<meta property="al:android:package" content="com.example.android/package" />
<meta property="al:android:app_name" content="app_name_android" />
<meta property="al:web:url" content="https://nextjs.dev.org.tw/web" />
<meta property="al:web:should_fallback" content="true" />

archives

描述歷史上感興趣的記錄、文件或其他材料的集合 (來源)。

layout.js | page.js
export const metadata = {
  archives: ['https://nextjs.dev.org.tw/13'],
}
<head> 輸出
<link rel="archives" href="https://nextjs.dev.org.tw/13" />

assets

layout.js | page.js
export const metadata = {
  assets: ['https://nextjs.dev.org.tw/assets'],
}
<head> 輸出
<link rel="assets" href="https://nextjs.dev.org.tw/assets" />

bookmarks

layout.js | page.js
export const metadata = {
  bookmarks: ['https://nextjs.dev.org.tw/13'],
}
<head> 輸出
<link rel="bookmarks" href="https://nextjs.dev.org.tw/13" />

category

layout.js | page.js
export const metadata = {
  category: 'technology',
}
<head> 輸出
<meta name="category" content="technology" />

facebook

您可以將 Facebook 應用程式或 Facebook 帳號連結到您的網頁,以使用特定的 Facebook 社群外掛程式 Facebook 文件

須知:您可以指定 appId 或 admins,但不能同時指定兩者。

layout.js | page.js
export const metadata = {
  facebook: {
    appId: '12345678',
  },
}
<head> 輸出
<meta property="fb:app_id" content="12345678" />
layout.js | page.js
export const metadata = {
  facebook: {
    admins: '12345678',
  },
}
<head> 輸出
<meta property="fb:admins" content="12345678" />

如果您想要產生多個 fb:admins meta 標籤,您可以使用陣列值。

layout.js | page.js
export const metadata = {
  facebook: {
    admins: ['12345678', '87654321'],
  },
}
<head> 輸出
<meta property="fb:admins" content="12345678" />
<meta property="fb:admins" content="87654321" />

other

所有中繼資料選項應涵蓋內建支援。然而,可能會有特定於您網站的自訂中繼資料標籤,或剛發布的全新中繼資料標籤。您可以使用 other 選項來呈現任何自訂中繼資料標籤。

layout.js | page.js
export const metadata = {
  other: {
    custom: 'meta',
  },
}
<head> 輸出
<meta name="custom" content="meta" />

如果您想要產生多個相同鍵的中繼資料標籤,您可以使用陣列值。

layout.js | page.js
export const metadata = {
  other: {
    custom: ['meta1', 'meta2'],
  },
}
<head> 輸出
<meta name="custom" content="meta1" /> <meta name="custom" content="meta2" />

不支援的中繼資料

以下中繼資料類型目前沒有內建支援。但是,它們仍然可以在版面配置或頁面本身中呈現。

Metadata建議
<meta http-equiv="...">透過 redirect()中介軟體安全性標頭 使用適當的 HTTP 標頭
<base>在版面配置或頁面本身中呈現標籤。
<noscript>在版面配置或頁面本身中呈現標籤。
<style>深入瞭解 Next.js 中的樣式設定
<script>深入瞭解 使用腳本
<link rel="stylesheet" />直接在版面配置或頁面本身中 import 樣式表。
<link rel="preload />使用 ReactDOM preload 方法
<link rel="preconnect" />使用 ReactDOM preconnect 方法
<link rel="dns-prefetch" />使用 ReactDOM prefetchDNS 方法

資源提示

<link> 元素具有許多 rel 關鍵字,可用於提示瀏覽器可能需要外部資源。瀏覽器會使用此資訊來應用預先載入最佳化,具體取決於關鍵字。

雖然 Metadata API 不直接支援這些提示,但您可以使用新的 ReactDOM 方法,將它們安全地插入到文件的 <head> 中。

app/preload-resources.tsx
'use client'
 
import ReactDOM from 'react-dom'
 
export function PreloadResources() {
  ReactDOM.preload('...', { as: '...' })
  ReactDOM.preconnect('...', { crossOrigin: '...' })
  ReactDOM.prefetchDNS('...')
 
  return '...'
}

在頁面呈現(瀏覽器)生命週期的早期開始載入資源。MDN 文件

ReactDOM.preload(href: string, options: { as: string })
<head> 輸出
<link rel="preload" href="..." as="..." />

搶先啟動與來源的連線。MDN 文件

ReactDOM.preconnect(href: string, options?: { crossOrigin?: string })
<head> 輸出
<link rel="preconnect" href="..." crossorigin />

嘗試在請求資源之前解析網域名稱。MDN 文件

ReactDOM.prefetchDNS(href: string)
<head> 輸出
<link rel="dns-prefetch" href="..." />

要知道:

  • 這些方法目前僅在用戶端元件中支援,這些元件在初始頁面載入時仍然是伺服器端呈現。
  • Next.js 內建功能,例如 next/fontnext/imagenext/script 會自動處理相關的資源提示。

類型

您可以使用 Metadata 類型為您的中繼資料新增類型安全。如果您在 IDE 中使用內建 TypeScript 外掛程式,則不需要手動新增類型,但如果您願意,仍然可以明確新增。

metadata 物件

layout.tsx | page.tsx
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'Next.js',
}

generateMetadata 函式

常規函式

layout.tsx | page.tsx
import type { Metadata } from 'next'
 
export function generateMetadata(): Metadata {
  return {
    title: 'Next.js',
  }
}

非同步函式

layout.tsx | page.tsx
import type { Metadata } from 'next'
 
export async function generateMetadata(): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}

使用區段屬性

layout.tsx | page.tsx
import type { Metadata } from 'next'
 
type Props = {
  params: Promise<{ id: string }>
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
 
export function generateMetadata({ params, searchParams }: Props): Metadata {
  return {
    title: 'Next.js',
  }
}
 
export default function Page({ params, searchParams }: Props) {}

使用父中繼資料

layout.tsx | page.tsx
import type { Metadata, ResolvingMetadata } from 'next'
 
export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  return {
    title: 'Next.js',
  }
}

JavaScript 專案

對於 JavaScript 專案,您可以使用 JSDoc 來新增類型安全。

layout.js | page.js
/** @type {import("next").Metadata} */
export const metadata = {
  title: 'Next.js',
}

串流中繼資料

從 v15.2 開始,generateMetadata 傳回的中繼資料將會串流到用戶端。這讓 Next.js 能夠在中繼資料解析後立即將其注入到 HTML 中。

由於頁面中繼資料通常主要針對機器人與爬蟲程式,Next.js 將繼續封鎖渲染,直到 HTML 受限的機器人解析中繼資料為止。

有些機器人(例如 Googlebot)可以執行 JavaScript,並且能夠檢查完整的頁面 DOM,這表示它們不需要封鎖中繼資料。但是,像 Twitterbot 這樣的機器人無法在爬取頁面時執行 JavaScript,它們屬於 HTML 受限類別。

Next.js 會自動偵測傳入請求的使用者代理程式,以判斷是否提供串流中繼資料或退回封鎖中繼資料。

如果您需要自訂此列表,您可以使用 next.config.js 中的 htmlLimitedBots 選項手動定義它們。當請求您的網頁時,Next.js 將確保符合此正規表示式的使用者代理程式收到封鎖中繼資料。指定 htmlLimitedBots 設定將覆寫 Next.js 的預設列表,讓您可以完全控制哪些使用者代理程式應選擇加入此行為。這是進階行為,預設設定對於大多數情況應該已足夠。

next.config.js
module.exports = {
  htmlLimitedBots: 'MySpecialBot|MyAnotherSpecialBot|SimpleCrawler',
}

注意: Next.js 包含 HTML 受限機器人的預設列表

版本歷史記錄

版本變更
v15.2.0generateMetadata 引入串流支援。
v13.2.0viewportthemeColorcolorScheme 已棄用,改用 viewport 設定
v13.2.0引入 metadatagenerateMetadata