Next.js
مسیریاب app
برنامه تان را بسیازید
بهینه سازی
Metadata

Metadata

Next.js یک API فرا داده (Metadata) دارد که برای تعریف metadata برنامه شما (مانند تگ‌های meta و link داخل المنت head HTML) جهت بهبود سئو و اشتراک‌پذیری در وب استفاده می‌شود.

دو روش برای افزودن Metadata به برنامه شما وجود دارد:

  • Metadata مبتنی بر پیکربندی: یک static metadata object یا یک تابع پویا generateMetadata را در یک فایل layout.js یا page.js خروجی بگیرید.
  • Metadata مبتنی بر فایل: فایل‌های ویژه استاتیک یا تولید شده داینامیک را به بخش‌های مسیر اضافه کنید.

با هر دوی این گزینه‌ها، Next.js به طور خودکار عناصر <head> مرتبط را برای صفحات شما ایجاد می‌کند. همچنین می‌توانید با استفاده از سازنده ImageResponse تصاویر OG پویا ایجاد کنید.

Metadata استاتیک

برای تعریف metadata استاتیک، یک آبجکت Metadata را از یک فایل layout.js یا page.js استاتیک صادر کنید.

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

برای مشاهده‌ی تمام گزینه‌های موجود، به بخش مرجع API مراجعه کنید.

Metadata داینامیک

می‌توانید از تابع generateMetadata برای fetch metadata ای که به مقادیر پویا نیاز دارد، استفاده کنید.

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> {
	// read route params
	const id = 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 استاتیک و پویا از طریق generateMetadata تنها در کامپوننت‌های سمت سرور پشتیبانی می‌شوند.
  • درخواست‌های fetch برای داده‌های مشابه در سراسر generateMetadata، generateStaticParams، طرح بندی ها (Layouts)، صفحات (Pages) و کامپوننت‌های سمت سرور به طور خودکار ذخیره‌سازی موقت (memoized) می‌شوند. در صورت عدم دسترسی به fetch، می‌توان از کش React استفاده کرد.
  • Next.js قبل از استریم کردن رابط کاربری به کلاینت، منتظر اتمام دریافت داده داخل generateMetadata می‌ماند. این کار تضمین می‌کند که بخش اول یک پاسخ استریم‌شده شامل تگ‌های <head> باشد.

metadata مبتنی بر فایل

این فایل‌های ویژه برای metadata در دسترس هستند:

می‌توانید از این موارد برای metadata استاتیک استفاده کنید، یا می‌توانید این فایل‌ها را با کد به صورت برنامه‌نویسی تولید کنید.

برای پیاده‌سازی و مثال ها، به بخش مرجع API فایل‌های Metadata و تولید پویای تصویر مراجعه کنید.

رفتار

metadata مبتنی بر فایل اولویت بالاتری دارد و هر metadata مبتنی بر پیکربندی را لغو می‌کند.

فیلدهای پیش‌فرض

دو تگ meta پیش‌فرض وجود دارد که حتی اگر یک مسیر metadata را تعریف نکند، همیشه اضافه می‌شوند:

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

خوب است بدانید: شما می‌توانید تگ پیش‌فرض viewport را بازنویسی کنید.

مرتب سازی

Metadata به ترتیب از بخش ریشه تا بخش نزدیک به صفحه نهایی page.js ارزیابی می شود. به عنوان مثال:

  1. app/layout.tsx (طرح بندی ریشه)
  2. app/blog/layout.tsx (Nested Blog Layout)
  3. app/blog/[slug]/page.tsx (Blog Page)

ادغام Merging

با پیروی از ترتیب ارزیابی، اشیاء Metadata که از چندین بخش در یک مسیر یکسان صادر می‌شوند، به طور سطحی shallowly با هم ادغام می‌شوند تا خروجی نهایی Metadata یک مسیر را تشکیل دهند. کلیدهای تکراری بر اساس ترتیب آنها جایگزین می شوند.

این بدان معناست که metadata با فیلدهای تودرتو مانند openGraph و robots که در یک بخش قبلی تعریف شده اند، توسط آخرین بخش برای تعریف آنها، بازنویسی می شوند.

بازنویسی فیلدها

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',
	},
}
 
// Output:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />

در مثال بالا:

  • title از app/layout.js با title در app/blog/page.js جایگزین می شود.
  • تمام فیلدهای openGraph از app/layout.js در app/blog/page.js جایگزین می شوند زیرا app/blog/page.js metadata openGraph را تنظیم می کند. به نبودن 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.js و app/about/page.js به اشتراک گذاشته می شود، در حالی که titles متفاوت هستند.

وراثت فیلدها

app/layout.js
export const metadata = {
	title: 'Acme',
	openGraph: {
		title: 'Acme',
		description: 'Acme is a...',
	},
}
app/about/page.js
export const metadata = {
	title: 'About',
}
 
// Output:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />

نکات

  • title از app/layout.js با title در app/about/page.js جایگزین می شود.
  • تمام فیلدهای openGraph از app/layout.js در app/about/page.js به ارث رسیده اند زیرا app/about/page.js metadata openGraph را تنظیم نمی کند.

تولید تصویر پویا

سازنده ImageResponse به شما امکان می‌دهد تصاویر پویایی با استفاده از JSX و CSS ایجاد کنید. این برای ایجاد تصاویر رسانه‌های اجتماعی مانند تصاویر Open Graph، کارت‌های توییتر و موارد دیگر مفید است.

برای استفاده از آن، می‌توانید ImageResponse را از next/og ایمپورت کنید.

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 به خوبی با دیگر API های Next.js مانند Route Handlers و Metadata مبتنی بر فایل یکپارچه می شود. به عنوان مثال، می توانید از ImageResponse در یک فایل opengraph-image.tsx برای تولید تصاویر Open Graph در زمان ساخت build یا به صورت پویا در زمان درخواست request استفاده کنید.

ImageResponse از ویژگی‌های رایج CSS پشتیبانی می‌کند، از جمله flexbox، absolute positioning، custom fonts، text wrapping، centering و nested images. لیست کامل ویژگی‌های CSS پشتیبانی‌شده را ببینید: لیست ویژگی‌های CSS پشتیبانی‌شده توسط ImageResponse

خوب است بدانید:

  • مثال هایی در Vercel OG Playground (opens in a new tab) در دسترس هستند.
  • ImageResponse از @vercel/og (opens in a new tab)، Satori (opens in a new tab) و Resvg برای تبدیل HTML و CSS به PNG استفاده می‌کند.
  • فقط Edge Runtime پشتیبانی می‌شود. Node.js پیش‌ فرض کار نخواهد کرد.
  • فقط از flexbox و زیرمجموعه‌ای از ویژگی‌های CSS پشتیبانی می‌شود. طرح بندی های پیشرفته (مانند display: grid) کار نخواهند کرد.
  • حداکثر حجم bundle 500KB است. حجم bundle شامل JSX، CSS، فونت‌ها، تصاویر و سایر دارایی‌های شما می‌شود. در صورت تجاوز از این مقدار، کاهش حجم دارایی‌ها یا دریافت آن‌ها در زمان اجرا را در نظر بگیرید.
  • فقط فرمت‌های فونت ttf، otf و woff پشتیبانی می‌شوند. برای بهینه‌سازی سرعت تجزیه‌ی فونت، ttf یا otf نسبت به woff ارجحیت دارند.

JSON-LD

JSON-LD (opens in a new tab) فرمتی برای داده‌های ساختاریافته است که می‌تواند توسط موتورهای جستجو برای درک محتوای شما استفاده شود. برای مثال، می‌توانید از آن برای توصیف یک فرد، رویداد، سازمان، فیلم، کتاب، دستور غذا و بسیاری دیگر از انواع موجودیت‌ها استفاده کنید.

توصیه فعلی ما برای JSON-LD این است که داده‌های ساختاریافته را به عنوان یک تگ <script> در کامپوننت‌های layout.js یا page.js خود ارائه دهید. برای نمونه:

app/products/[id]/page.tsx
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>
			{/* Add JSON-LD to your page */}
			<script
				type="application/ld+json"
				dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
			/>
			{/* ... */}
		</section>
	)
}

شما می‌توانید داده‌های ساختاریافته‌ی خود را با ابزار Rich Results Test (opens in a new tab) برای گوگل یا Schema Markup Validator (opens in a new tab) تأیید و تست کنید.

می‌توانید JSON-LD خود را با TypeScript با استفاده از پکیج های community مانند schema-dts (opens in a new tab) تایپ کنید.

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