البيانات الوصفية (Metadata)
يحتوي Next.js على Metadata API يمكن استخدامه لتعريف البيانات الوصفية لتطبيقك (مثل علامات meta
و link
داخل عنصر head
في HTML) لتحسين تحسين محركات البحث (SEO) وإمكانية المشاركة على الويب.
هناك طريقتان لإضافة بيانات وصفية لتطبيقك:
- البيانات الوصفية المعتمدة على التكوين: قم بتصدير كائن
metadata
ثابت أو دالةgenerateMetadata
ديناميكية في ملفlayout.js
أوpage.js
. - البيانات الوصفية المعتمدة على الملفات: أضف ملفات خاصة ثابتة أو مُنشأة ديناميكيًا إلى مقاطع المسار.
مع هذين الخيارين، سيقوم Next.js تلقائيًا بإنشاء عناصر <head>
ذات الصلة لصفحاتك. يمكنك أيضًا إنشاء صور OG ديناميكية باستخدام منشئ ImageResponse
.
البيانات الوصفية الثابتة
لتعريف البيانات الوصفية الثابتة، قم بتصدير كائن Metadata
من ملف layout.js
أو ملف page.js
ثابت.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '...',
description: '...',
}
export default function Page() {}
export const metadata = {
title: '...',
description: '...',
}
export default function Page() {}
لجميع الخيارات المتاحة، راجع مرجع API.
البيانات الوصفية الديناميكية
يمكنك استخدام دالة generateMetadata
لجلب البيانات الوصفية التي تتطلب قيمًا ديناميكية.
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())
// الوصول الاختياري إلى البيانات الوصفية الأصلية وتوسيعها (بدلاً من استبدالها)
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) {}
export async function generateMetadata({ params, searchParams }, parent) {
// قراءة معلمات المسار
const id = params.id
// جلب البيانات
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// الوصول الاختياري إلى البيانات الوصفية الأصلية وتوسيعها (بدلاً من استبدالها)
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
export default function Page({ params, searchParams }) {}
لجميع المعلمات المتاحة، راجع مرجع API.
معلومة مفيدة:
- كل من البيانات الوصفية الثابتة والديناميكية عبر
generateMetadata
مدعومة فقط في مكونات الخادم (Server Components).- طلبات
fetch
يتم تخزينها مؤقتًا تلقائيًا لنفس البيانات عبرgenerateMetadata
،generateStaticParams
، التخطيطات، الصفحات، ومكونات الخادم. يمكن استخدامcache
من React إذا كانfetch
غير متاح.- سينتظر Next.js اكتمال جلب البيانات داخل
generateMetadata
قبل بث واجهة المستخدم إلى العميل. هذا يضمن أن الجزء الأول من الاستجابة المبثوثة يتضمن علامات<head>
.
البيانات الوصفية المعتمدة على الملفات
هذه الملفات الخاصة متاحة للبيانات الوصفية:
- favicon.ico, apple-icon.jpg, and icon.jpg
- opengraph-image.jpg and twitter-image.jpg
- robots.txt
- sitemap.xml
يمكنك استخدام هذه الملفات للبيانات الوصفية الثابتة، أو يمكنك إنشاء هذه الملفات برمجيًا باستخدام الكود.
للتنفيذ والأمثلة، راجع مرجع Metadata Files API و إنشاء الصور الديناميكية.
السلوك
البيانات الوصفية المعتمدة على الملفات لها أولوية أعلى وستتجاوز أي بيانات وصفية معتمدة على التكوين.
الحقول الافتراضية
هناك علامتي meta
افتراضيتين تتم إضافتهما دائمًا حتى إذا لم يحدد المسار بيانات وصفية:
- علامة meta charset تحدد ترميز الأحرف للموقع.
- علامة meta viewport تحدد عرض viewport ومقياسه ليتناسب مع الأجهزة المختلفة.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
معلومة مفيدة: يمكنك تجاوز علامة
viewport
الافتراضية.
الترتيب
يتم تقييم البيانات الوصفية بالترتيب، بدءًا من مقطع الجذر وصولاً إلى المقطع الأقرب إلى مقطع page.js
النهائي. على سبيل المثال:
app/layout.tsx
(تخطيط الجذر)app/blog/layout.tsx
(تخطيط المدونة المتداخل)app/blog/[slug]/page.tsx
(صفحة المدونة)
الدمج
باتباع ترتيب التقييم، يتم دمج كائنات البيانات الوصفية المصدرة من مقاطع متعددة في نفس المسار بشكل سطحي لتشكيل ناتج البيانات الوصفية النهائي للمسار. يتم استبدال المفاتيح المكررة بناءً على ترتيبها.
هذا يعني أن البيانات الوصفية ذات الحقول المتداخلة مثل openGraph
و robots
التي تم تعريفها في مقطع سابق يتم تجاوزها بواسطة آخر مقطع يقوم بتعريفها.
تجاوز الحقول
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
}
export const metadata = {
title: 'Blog',
openGraph: {
title: 'Blog',
},
}
// الناتج:
// <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
يحدد بياناتopenGraph
. لاحظ غياب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',
}
// الناتج:
// <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
لا يحدد بياناتopenGraph
.
إنشاء الصور الديناميكية
يسمح منشئ ImageResponse
بإنشاء صور ديناميكية باستخدام JSX و CSS. هذا مفيد لإنشاء صور وسائل التواصل الاجتماعي مثل صور Open Graph وبطاقات Twitter وغيرها.
يستخدم ImageResponse
Edge Runtime، ويقوم Next.js تلقائيًا بإضافة العناوين الصحيحة للصور المخزنة مؤقتًا عند الحافة، مما يساعد في تحسين الأداء وتقليل إعادة الحساب.
لاستخدامه، يمكنك استيراد ImageResponse
من next/og
:
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
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 الأخرى، بما في ذلك Route Handlers والبيانات الوصفية المعتمدة على الملفات. على سبيل المثال، يمكنك استخدام ImageResponse
في ملف opengraph-image.tsx
لإنشاء صور Open Graph أثناء وقت البناء أو ديناميكيًا عند وقت الطلب.
يدعم ImageResponse
خصائص CSS الشائعة بما في ذلك flexbox والتحديد المطلق، الخطوط المخصصة، التفاف النص، المركزة، والصور المتداخلة. راجع القائمة الكاملة لخصائص CSS المدعومة.
معلومة مفيدة:
- تتوفر أمثلة في Vercel OG Playground.
- يستخدم
ImageResponse
@vercel/og، Satori، و Resvg لتحويل HTML و CSS إلى PNG.- فقط Edge Runtime مدعوم. لن يعمل Node.js الافتراضي.
- فقط flexbox ومجموعة فرعية من خصائص CSS مدعومة. التخطيطات المتقدمة (مثل
display: grid
) لن تعمل.- الحد الأقصى لحجم الحزمة هو
500KB
. يشمل حجم الحزمة JSX، CSS، الخطوط، الصور، وأي أصول أخرى. إذا تجاوزت الحد، فكر في تقليل حجم أي أصول أو جلبها أثناء التشغيل.- فقط تنسيقات الخطوط
ttf
،otf
، وwoff
مدعومة. لتعظيم سرعة تحليل الخط، يُفضل استخدامttf
أوotf
بدلاً منwoff
.
JSON-LD
JSON-LD هو تنسيق للبيانات المنظمة التي يمكن استخدامها من قبل محركات البحث لفهم محتواك. على سبيل المثال، يمكنك استخدامه لوصف شخص، حدث، منظمة، فيلم، كتاب، وصفة، والعديد من أنواع الكيانات الأخرى.
توصيتنا الحالية لـ JSON-LD هي عرض البيانات المنظمة كعلامة <script>
في مكونات layout.js
أو page.js
. على سبيل المثال:
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>
{/* إضافة JSON-LD إلى صفحتك */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
)
}
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>
{/* إضافة JSON-LD إلى صفحتك */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* ... */}
</section>
)
}
يمكنك التحقق من صحة بياناتك المنظمة واختبارها باستخدام Rich Results Test من Google أو Schema Markup Validator العام.
يمكنك كتابة JSON-LD باستخدام TypeScript باستخدام حزم المجتمع مثل schema-dts
:
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.',
}