البيانات الوصفية (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
يمكنك استخدام هذه الملفات للبيانات الوصفية الثابتة، أو يمكنك إنشاء هذه الملفات برمجيًا باستخدام التعليمات البرمجية.
للتنفيذ والأمثلة، راجع مرجع ملفات البيانات الوصفية وإنشاء الصور الديناميكية.
السلوك
البيانات الوصفية المعتمدة على الملفات لها أولوية أعلى وستتجاوز أي بيانات وصفية معتمدة على التكوين.
الحقول الافتراضية
هناك علامتان 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/server
:
import { ImageResponse } from 'next/server'
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 Runtime الافتراضي.
- يتم دعم 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.',
}