Metadata
Next.js 具有 Metadata API,可用於定義您的應用程式 metadata(例如 HTML head
元素內的 meta
和 link
標籤),以改善 SEO 和網路分享性。
有兩種方式可以將 metadata 新增至您的應用程式
- 基於設定的 Metadata:在
layout.js
或page.js
檔案中匯出靜態metadata
物件或動態generateMetadata
函式。 - 基於檔案的 Metadata:將靜態或動態產生的特殊檔案新增至路由區段。
透過這兩種選項,Next.js 將自動為您的頁面產生相關的 <head>
元素。您也可以使用 ImageResponse
建構函式建立動態 OG 圖片。
靜態 Metadata
若要定義靜態 metadata,請從 layout.js
或靜態 page.js
檔案匯出 Metadata
物件。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '...',
description: '...',
}
export default function Page() {}
如需所有可用選項,請參閱 API 參考。
動態 Metadata
您可以使用 generateMetadata
函式來 fetch
需要動態值的 metadata。
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) {}
如需所有可用的參數,請參閱 API 參考。
要知道:
基於檔案的 metadata
這些特殊檔案可用於 metadata
- favicon.ico、apple-icon.jpg 和 icon.jpg
- opengraph-image.jpg 和 twitter-image.jpg
- robots.txt
- sitemap.xml
您可以將這些用於靜態 metadata,也可以使用程式碼以程式設計方式產生這些檔案。
如需實作和範例,請參閱 Metadata 檔案 API 參考和動態圖片產生。
行為
基於檔案的 metadata 具有較高的優先順序,並且會覆寫任何基於設定的 metadata。
預設欄位
即使路由未定義 metadata,也始終會新增兩個預設的 meta
標籤
- meta charset 標籤 設定網站的字元編碼。
- meta viewport 標籤 設定網站的 viewport 寬度和縮放比例,以針對不同的裝置進行調整。
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
要知道:您可以覆寫預設的
viewport
meta 標籤。
排序
Metadata 會依序評估,從根區段開始,向下到最接近最終 page.js
區段的區段。例如
app/layout.tsx
(根版面配置)app/blog/layout.tsx
(巢狀部落格版面配置)app/blog/[slug]/page.tsx
(部落格頁面)
合併
依照評估順序,從同一路由中多個區段匯出的 Metadata 物件會淺層合併在一起,以形成路由的最終 metadata 輸出。重複的鍵會根據其順序取代。
這表示在較早區段中定義的巢狀欄位 metadata(例如 openGraph
和 robots
)會被最後一個定義它們的區段覆寫。
覆寫欄位
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
}
export const metadata = {
title: 'Blog',
openGraph: {
title: 'Blog',
},
}
// Output:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />
在上述範例中
app/layout.js
中的title
會被app/blog/page.js
中的title
取代。app/layout.js
中的所有openGraph
欄位都會在app/blog/page.js
中被取代,因為app/blog/page.js
設定了openGraph
metadata。請注意,缺少了openGraph.description
。
如果您想要在區段之間共用某些巢狀欄位,同時覆寫其他欄位,您可以將它們拉出到個別變數中
export const openGraphImage = { images: ['http://...'] }
import { openGraphImage } from './shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Home',
},
}
import { openGraphImage } from '../shared-metadata'
export const metadata = {
openGraph: {
...openGraphImage,
title: 'About',
},
}
在上述範例中,OG 圖片在 app/layout.js
和 app/about/page.js
之間共用,而標題則不同。
繼承欄位
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
}
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.js
中的title
會被app/about/page.js
中的title
取代。app/layout.js
中的所有openGraph
欄位都會在app/about/page.js
中被繼承,因為app/about/page.js
未設定openGraph
metadata。
動態圖片產生
ImageResponse
建構函式可讓您使用 JSX 和 CSS 產生動態圖片。這對於建立社群媒體圖片(例如 Open Graph 圖片、Twitter 卡片等)非常有用。
若要使用它,您可以從 next/og
匯入 ImageResponse
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 (包括 路由處理器和基於檔案的 Metadata) 良好整合。例如,您可以在 opengraph-image.tsx
檔案中使用 ImageResponse
,以在建置時或在請求時動態產生 Open Graph 圖片。
ImageResponse
支援常見的 CSS 屬性,包括 flexbox 和絕對定位、自訂字型、文字換行、置中和巢狀圖片。請參閱支援的 CSS 屬性完整清單。
要知道:
- 範例可在 Vercel OG Playground 中找到。
ImageResponse
使用 @vercel/og、Satori 和 Resvg,以將 HTML 和 CSS 轉換為 PNG。- 僅支援 flexbox 和 CSS 屬性的子集。進階版面配置(例如
display: grid
)將無法運作。- 最大捆綁大小為
500KB
。捆綁大小包括您的 JSX、CSS、字型、圖片和任何其他資源。如果您超出限制,請考慮縮減任何資源的大小或在執行階段抓取。- 僅支援
ttf
、otf
和woff
字型格式。為了最大化字型剖析速度,ttf
或otf
優於woff
。
JSON-LD
JSON-LD 是一種結構化資料格式,搜尋引擎可以使用它來理解您的內容。例如,您可以使用它來描述一個人、一個事件、一個組織、一部電影、一本書、一個食譜和許多其他類型的實體。
我們目前對於 JSON-LD 的建議是在您的 layout.js
或 page.js
元件中將結構化資料渲染為 <script>
標籤。例如
export default async function Page({ params }) {
const product = await getProduct((await params).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 的 Rich Results Test 或通用的 Schema Markup Validator 來驗證和測試您的結構化資料。
您可以使用社群套件(例如 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.dev.org.tw/imgs/sticker.png',
description: 'Dynamic at the speed of static.',
}
下一步
這有幫助嗎?