Menu

generateMetadata

此页面涵盖了使用 generateMetadata 和静态 metadata 对象的所有基于配置的 Metadata 选项。

layout.tsx
import type { Metadata } from "next";
 
// 静态 metadata
export const metadata: Metadata = {
  title: "...",
};
 
// 或动态 metadata
export async function generateMetadata({ params }) {
  return {
    title: "...",
  };
}
layout.js
// 静态 metadata
export const metadata = {
  title: "...",
};
 
// 或动态 metadata
export async function generateMetadata({ params }) {
  return {
    title: "...",
  };
}

值得注意的是:

  • metadata 对象和 generateMetadata 函数导出仅在服务器组件中支持
  • 你不能在同一路由段中同时导出 metadata 对象和 generateMetadata 函数。

metadata 对象

要定义静态 metadata,从 layout.jspage.js 文件中导出一个 Metadata 对象

layout.tsx
import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: "...",
  description: "...",
};
 
export default function Page() {}
layout.js
export const 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: { id: string };
  searchParams: { [key: string]: string | string[] | undefined };
};
 
export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  // 读取路由参数
  const id = params.id;
 
  // 获取数据
  const product = await fetch(`https://.../${id}`).then((res) => res.json());
 
  // 可选地访问和扩展(而不是替换)父 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) {}
app/products/[id]/page.js
export async function generateMetadata({ params, searchParams }, parent) {
  // 读取路由参数
  const id = params.id;
 
  // 获取数据
  const product = await fetch(`https://.../${id}`).then((res) => res.json());
 
  // 可选地访问和扩展(而不是替换)父 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 }) {}

参数

generateMetadata 函数接受以下参数:

  • props - 一个包含当前路由参数的对象:

    • params - 一个包含从根段到调用 generateMetadata 的段的动态路由参数对象。例如:

      路由URLparams
      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 - 一个包含当前 URL 的搜索参数的对象。例如:

      URLsearchParams
      /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 来定义。
  • generateMetadatagenerateStaticParams、Layouts、Pages 和 Server Components 中,对相同数据的 fetch 请求会自动记忆化。如果 fetch 不可用,可以使用 React cache
  • searchParams 仅在 page.js 段中可用。
  • Next.js 的 redirect()notFound() 方法也可以在 generateMetadata 内部使用。

Metadata 字段

title

title 属性用于设置文档的标题。它可以定义为简单的字符串或可选的模板对象

字符串

layout.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: "...",
  },
};
app/layout.js
export const metadata = {
  title: {
    default: "...",
    template: "...",
    absolute: "...",
  },
};
默认值

title.default 可用于为未定义 title 的子路由段提供一个后备标题

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 = {};
 
// 输出: <title>Acme</title>
模板

title.template 可用于为路由段中定义的 titles 添加前缀或后缀。

app/layout.tsx
import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: {
    template: "%s | Acme",
    default: "Acme", // 创建模板时需要一个默认值
  },
};
app/layout.js
export const metadata = {
  title: {
    template: "%s | Acme",
    default: "Acme", // 创建模板时需要一个默认值
  },
};
app/about/page.tsx
import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: "About",
};
 
// 输出: <title>About | Acme</title>
app/about/page.js
export const metadata = {
  title: "About",
};
 
// 输出: <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/layout.js
export const metadata = {
  title: {
    template: "%s | Acme",
  },
};
app/about/page.tsx
import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: {
    absolute: "About",
  },
};
 
// 输出: <title>About</title>
app/about/page.js
export const metadata = {
  title: {
    absolute: "About",
  },
};
 
// 输出: <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
export const metadata = {
  description: "用于 Web 的 React 框架",
};
<head>
<meta name="description" content="用于 Web 的 React 框架" />

基本字段

layout.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.org" }],
  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.org" />
<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 是一个便利选项,用于为需要完全限定 URL 的 metadata 字段设置基本 URL 前缀。

  • metadataBase 允许当前路由段及其以下定义的基于 URL 的 metadata 字段使用相对路径,而不是原本需要的绝对 URL。
  • 该字段的相对路径将与 metadataBase 组合形成一个完全限定的 URL。
  • 如果未配置,metadataBase自动填充默认值
layout.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 中设置,以应用于所有路由的基于 URL 的 metadata 字段。
  • 所有需要绝对 URL 的基于 URL 的 metadata 字段都可以用 metadataBase 选项配置。
  • metadataBase 可以包含子域名,例如 https://app.acme.com 或基本路径,例如 https://acme.com/start/from/here
  • 如果 metadata 字段提供了绝对 URL,则会忽略 metadataBase
  • 在基于 URL 的 metadata 字段中使用相对路径而不配置 metadataBase 将导致构建错误。
  • Next.js 将规范化 metadataBase(例如 https://acme.com/)和相对字段(例如 /path)之间的重复斜杠为单个斜杠(例如 https://acme.com/path)

默认值

如果未配置,metadataBase 有一个默认值

在 Vercel 上:

  • 对于生产部署,将使用 VERCEL_PROJECT_PRODUCTION_URL
  • 对于预览部署,VERCEL_BRANCH_URL 将优先使用,如果不存在则回退到 VERCEL_URL

如果这些值存在,它们将被用作 metadataBase默认值,否则会回退到 http://localhost:${process.env.PORT || 3000}。这允许 Open Graph 图像在本地构建和 Vercel 预览及生产部署上都能正常工作。当覆盖默认值时,我们建议使用环境变量来计算 URL。这允许为本地开发、暂存和生产环境配置 URL。

系统环境变量文档中查看有关这些环境变量的更多详细信息。

URL 组合

URL 组合优先考虑开发者意图,而不是默认的目录遍历语义。

  • metadataBasemetadata 字段之间的尾部斜杠会被规范化。
  • metadata 字段中的"绝对"路径(通常会替换整个 URL 路径)被视为"相对"路径(从 metadataBase 的末尾开始)。

例如,给定以下 metadataBase:

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

任何继承上述 metadataBase 并设置自己的值的 metadata 字段将按如下方式解析:

metadata 字段解析后的 URL
/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
export const metadata = {
  openGraph: {
    title: "Next.js",
    description: "The React Framework for the Web",
    url: "https://nextjs.org",
    siteName: "Next.js",
    images: [
      {
        url: "https://nextjs.org/og.png", // 必须是绝对 URL
        width: 800,
        height: 600,
      },
      {
        url: "https://nextjs.org/og-alt.png", // 必须是绝对 URL
        width: 1800,
        height: 1600,
        alt: "My custom alt",
      },
    ],
    videos: [
      {
        url: "https://nextjs.org/video.mp4", // 必须是绝对 URL
        width: 800,
        height: 600,
      },
    ],
    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.org/" />
<meta property="og:site_name" content="Next.js" />
<meta property="og:locale" content="en_US" />
<meta property="og:image:url" content="https://nextjs.org/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
<meta property="og:image:url" content="https://nextjs.org/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:type" content="website" />
layout.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 图像,使用基于文件的元数据 API可能更方便。与其必须同步配置导出和实际文件,基于文件的 API 将自动为您生成正确的元数据。

robots

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

icons

值得注意的是: 我们建议尽可能使用基于文件的元数据 API来处理图标。与其必须同步配置导出和实际文件,基于文件的 API 将自动为您生成正确的元数据。

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

值得注意的是: msapplication-* 元标签在 Microsoft Edge 的 Chromium 版本中不再受支持,因此不再需要。

themeColor

已废弃: 自 Next.js 14 起,metadata 中的 themeColor 选项已废弃。请改用 viewport 配置

manifest

Web 应用程序清单,定义在 Web 应用程序清单规范中。

layout.js
export const metadata = {
  manifest: "https://nextjs.org/manifest.json",
};
<head>
<link rel="manifest" href="https://nextjs.org/manifest.json" />

twitter

Twitter 规范(令人惊讶的是)不仅仅用于 X(前身为 Twitter)。

了解更多关于 Twitter 卡片标记参考的信息。

layout.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.org/og.png"], // 必须是绝对 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.org/og.png" />
layout.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.org/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.org/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
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
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="apple-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
export const metadata = {
  alternates: {
    canonical: "https://nextjs.org",
    languages: {
      "en-US": "https://nextjs.org/en-US",
      "de-DE": "https://nextjs.org/de-DE",
    },
    media: {
      "only screen and (max-width: 600px)": "https://nextjs.org/mobile",
    },
    types: {
      "application/rss+xml": "https://nextjs.org/rss",
    },
  },
};
<head>
<link rel="canonical" href="https://nextjs.org" />
<link rel="alternate" hreflang="en-US" href="https://nextjs.org/en-US" />
<link rel="alternate" hreflang="de-DE" href="https://nextjs.org/de-DE" />
<link
  rel="alternate"
  media="only screen and (max-width: 600px)"
  href="https://nextjs.org/mobile"
/>
<link
  rel="alternate"
  type="application/rss+xml"
  href="https://nextjs.org/rss"
/>
layout.js
export const metadata = {
  appLinks: {
    ios: {
      url: "https://nextjs.org/ios",
      app_store_id: "app_store_id",
    },
    android: {
      package: "com.example.android/package",
      app_name: "app_name_android",
    },
    web: {
      url: "https://nextjs.org/web",
      should_fallback: true,
    },
  },
};
<head>
<meta property="al:ios:url" content="https://nextjs.org/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.org/web" />
<meta property="al:web:should_fallback" content="true" />

archives

提供一个指向历史记录、文档或其他具有历史意义的材料集合的链接(来源)。

layout.js
export const metadata = {
  archives: ["https://nextjs.org/13"],
};
<head>
<link rel="archives" href="https://nextjs.org/13" />

assets

layout.js
export const metadata = {
  assets: ["https://nextjs.org/assets"],
};
<head>
<link rel="assets" href="https://nextjs.org/assets" />

bookmarks

layout.js
export const metadata = {
  bookmarks: ["https://nextjs.org/13"],
};
<head>
<link rel="bookmarks" href="https://nextjs.org/13" />

category

layout.js
export const metadata = {
  category: "technology",
};
<head>
<meta name="category" content="technology" />

facebook

您可以将Facebook应用或Facebook账户连接到您的网页,以便使用某些Facebook社交插件 Facebook文档

值得注意的是:您可以指定appId或admins,但不能同时指定两者。

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

如果您想生成多个fb:admins元标签,可以使用数组值。

layout.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
export const metadata = {
  other: {
    custom: "meta",
  },
};
<head>
<meta name="custom" content="meta" />

如果您想生成多个相同键的元标签,可以使用数组值。

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

不支持的元数据

以下元数据类型目前没有内置支持。但是,它们仍然可以在布局或页面本身中进行渲染。

元数据建议
<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 关键字,可用于向浏览器暗示可能需要外部资源。浏览器使用此信息根据关键字应用预加载优化。

虽然元数据 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 "...";
}
app/preload-resources.js
"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
import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: "Next.js",
};

generateMetadata 函数

常规函数

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

异步函数

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

带有段 props

layout.tsx
import type { Metadata } from "next";
 
type Props = {
  params: { id: string };
  searchParams: { [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
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
/** @type {import("next").Metadata} */
export const metadata = {
  title: "Next.js",
};

版本历史

版本变更
v13.2.0viewportthemeColorcolorScheme 已弃用,改为使用 viewport 配置
v13.2.0引入了 metadatagenerateMetadata