Menu

Metadata and OG images

Metadata API 可用于定义你的应用程序元数据,以改善 SEO 和网页可分享性,包括:

  1. 静态 metadata 对象
  2. 动态 generateMetadata 函数
  3. 特殊的文件约定,可用于添加静态或动态生成的 faviconsOG 图像

通过上述所有选项,Next.js 将自动为你的页面生成相关的 <head> 标签,可以在浏览器的开发者工具中检查。

metadata 对象和 generateMetadata 函数导出仅在服务器组件中支持。

默认字段

有两个默认的 meta 标签始终会被添加,即使路由没有定义元数据:

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

其他元数据字段可以使用 Metadata 对象(用于静态元数据)或 generateMetadata 函数(用于生成的元数据)来定义。

静态元数据

要定义静态元数据,从静态的 layout.jspage.js 文件中导出一个 Metadata 对象。例如,为博客路由添加标题和描述:

app/blog/layout.tsx
TypeScript
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'My Blog',
  description: '...',
}
 
export default function Layout() {}

你可以在 generateMetadata 文档中查看完整的可用选项列表。

生成的元数据

你可以使用 generateMetadata 函数来 fetch 依赖于数据的元数据。例如,为特定博客文章获取标题和描述:

app/blog/[slug]/page.tsx
TypeScript
import type { Metadata, ResolvingMetadata } from 'next'
 
type Props = {
  params: Promise<{ slug: string }>
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
 
export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const slug = (await params).slug
 
  // 获取文章信息
  const post = await fetch(`https://api.vercel.app/blog/${slug}`).then((res) =>
    res.json()
  )
 
  return {
    title: post.title,
    description: post.description,
  }
}
 
export default function Page({ params, searchParams }: Props) {}

流式传输元数据

对于动态渲染的页面,Next.js 会单独流式传输元数据,一旦 generateMetadata 解析完成就将其注入到 HTML 中,而不会阻塞 UI 渲染。

流式传输元数据通过允许视觉内容首先流式传输来提高感知性能。

对于期望元数据在 <head> 标签中的机器人和爬虫(例如 TwitterbotSlackbotBingbot),流式传输元数据是禁用的。这些通过使用传入请求的 User Agent 头来检测。

你可以在 Next.js 配置文件中使用 htmlLimitedBots 选项自定义或完全禁用流式传输元数据。

静态渲染的页面不使用流式传输,因为元数据在构建时就已解析。

了解更多关于流式传输元数据的信息。

记忆化数据请求

在某些情况下,你可能需要为元数据和页面本身获取相同的数据。为了避免重复请求,你可以使用 React 的 cache 函数来记忆化返回值,只获取一次数据。例如,为元数据和页面获取博客文章信息:

app/lib/data.ts
TypeScript
import { cache } from 'react'
import { db } from '@/app/lib/db'
 
// getPost 将被使用两次,但只执行一次
export const getPost = cache(async (slug: string) => {
  const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })
  return res
})
app/blog/[slug]/page.tsx
TypeScript
import { getPost } from '@/app/lib/data'
 
export async function generateMetadata({
  params,
}: {
  params: { slug: string }
}) {
  const post = await getPost(params.slug)
  return {
    title: post.title,
    description: post.description,
  }
}
 
export default async function Page({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug)
  return <div>{post.title}</div>
}

基于文件的元数据

以下特殊文件可用于元数据:

你可以将这些用于静态元数据,或者可以使用代码以编程方式生成这些文件。

Favicons

Favicons 是在书签和搜索结果中代表你网站的小图标。要向你的应用程序添加 favicon,创建一个 favicon.ico 并将其添加到 app 文件夹的根目录。

Favicon Special File inside the App Folder with sibling layout and page files

你也可以使用代码以编程方式生成 favicons。有关更多信息,请参阅 favicon 文档

静态 Open Graph 图像

Open Graph (OG) 图像是在社交媒体上代表你网站的图像。要向你的应用程序添加静态 OG 图像,在 app 文件夹的根目录创建一个 opengraph-image.png 文件。

OG image special file inside the App folder with sibling layout and page files

你还可以通过在文件夹结构中更深的位置创建 opengraph-image.png 来为特定路由添加 OG 图像。例如,要创建特定于 /blog 路由的 OG 图像,在 blog 文件夹内添加一个 opengraph-image.jpg 文件。

OG image special file inside the blog folder

更具体的图像将优先于文件夹结构中其上方的任何 OG 图像。

也支持其他图像格式,如 jpegpnggif。有关更多信息,请参阅 Open Graph Image 文档

生成的 Open Graph 图像

ImageResponse 构造函数允许你使用 JSX 和 CSS 生成动态图像。这对于依赖于数据的 OG 图像很有用。

例如,要为每篇博客文章生成唯一的 OG 图像,在 blog 文件夹内添加一个 opengraph-image.tsx 文件,并从 next/og 导入 ImageResponse 构造函数:

app/blog/[slug]/opengraph-image.tsx
TypeScript
import { ImageResponse } from 'next/og'
import { getPost } from '@/app/lib/data'
 
// 图像元数据
export const size = {
  width: 1200,
  height: 630,
}
 
export const contentType = 'image/png'
 
// 图像生成
export default async function Image({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug)
 
  return new ImageResponse(
    (
      // ImageResponse JSX 元素
      <div
        style={{
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        {post.title}
      </div>
    )
  )
}

ImageResponse 支持常见的 CSS 属性,包括 flexbox 和绝对定位、自定义字体、文本换行、居中和嵌套图像。查看支持的 CSS 属性的完整列表

值得注意的是

  • 示例可在 Vercel OG Playground 中找到。
  • ImageResponse 使用 @vercel/ogsatoriresvg 将 HTML 和 CSS 转换为 PNG。
  • 仅支持 flexbox 和 CSS 属性的子集。高级布局(例如 display: grid)将不起作用。