كيفية تنفيذ التحديث الثابت التدريجي (ISR)
يتيح لك التحديث الثابت التدريجي (ISR) ما يلي:
- تحديث المحتوى الثابت دون إعادة بناء الموقع بالكامل
- تقليل حمل الخادم عن طريق تقديم صفحات ثابتة مسبقة التصيير لمعظم الطلبات
- ضمان إضافة رؤوس
cache-control
المناسبة تلقائيًا للصفحات - التعامل مع أعداد كبيرة من صفحات المحتوى دون أوقات بناء طويلة لـ
next build
إليك مثالًا بسيطًا:
interface Post {
id: string
title: string
content: string
}
// سيقوم Next.js بإبطال ذاكرة التخزين المؤقت عندما
// يصل طلب، على الأكثر مرة كل 60 ثانية.
export const revalidate = 60
// سنقوم بمسبق تصيير المعلمات من `generateStaticParams` فقط أثناء وقت البناء.
// إذا وصل طلب لمسار لم يتم إنشاؤه،
// سيقوم Next.js بتصيير الصفحة على الخادم عند الطلب.
export const dynamicParams = true // أو false، لإظهار خطأ 404 للمسارات غير المعروفة
export async function generateStaticParams() {
const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
return posts.map((post) => ({
id: String(post.id),
}))
}
export default async function Page({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const post: Post = await fetch(`https://api.vercel.app/blog/${id}`).then(
(res) => res.json()
)
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
// سيقوم Next.js بإبطال ذاكرة التخزين المؤقت عندما
// يصل طلب، على الأكثر مرة كل 60 ثانية.
export const revalidate = 60
// سنقوم بمسبق تصيير المعلمات من `generateStaticParams` فقط أثناء وقت البناء.
// إذا وصل طلب لمسار لم يتم إنشاؤه،
// سيقوم Next.js بتصيير الصفحة على الخادم عند الطلب.
export const dynamicParams = true // أو false، لإظهار خطأ 404 للمسارات غير المعروفة
export async function generateStaticParams() {
const posts = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
return posts.map((post) => ({
id: String(post.id),
}))
}
export default async function Page({ params }) {
const { id } = await params
const post = await fetch(`https://api.vercel.app/blog/${id}`).then((res) =>
res.json()
)
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
إليك كيفية عمل هذا المثال:
- أثناء
next build
، يتم إنشاء جميع منشورات المدونة المعروفة (هناك 25 في هذا المثال) - جميع الطلبات الموجهة إلى هذه الصفحات (مثل
/blog/1
) مخزنة مؤقتًا وفورية - بعد مرور 60 ثانية، سيظل الطلب التالي يعرض الصفحة المخزنة (القديمة)
- يتم إبطال ذاكرة التخزين المؤقت ويبدأ إنشاء نسخة جديدة من الصفحة في الخلفية
- بمجرد الإنشاء بنجاح، سيعرض Next.js الصفحة المحدثة ويخزنها مؤقتًا
- إذا تم طلب
/blog/26
، سيقوم Next.js بإنشاء هذه الصفحة وتخزينها مؤقتًا عند الطلب
مرجع
تكوين جزء المسار
الدوال
أمثلة
إعادة التحقق بناءً على الوقت
هذا يسترد ويعرض قائمة بمنشورات المدونة على /blog
. بعد ساعة، يتم إبطال ذاكرة التخزين المؤقت لهذه الصفحة عند الزيارة التالية للصفحة. ثم، في الخلفية، يتم إنشاء نسخة جديدة من الصفحة بأحدث منشورات المدونة.
interface Post {
id: string
title: string
content: string
}
export const revalidate = 3600 // إبطال كل ساعة
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog')
const posts: Post[] = await data.json()
return (
<main>
<h1>منشورات المدونة</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</main>
)
}
export const revalidate = 3600 // إبطال كل ساعة
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog')
const posts = await data.json()
return (
<main>
<h1>منشورات المدونة</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</main>
)
}
نوصي بتعيين وقت إعادة تحقق طويل. على سبيل المثال، ساعة بدلاً من ثانية. إذا كنت بحاجة إلى دقة أكبر، ففكر في استخدام إعادة التحقق عند الطلب. إذا كنت بحاجة إلى بيانات في الوقت الفعلي، ففكر في التبديل إلى التصيير الديناميكي.
إعادة التحقق عند الطلب باستخدام revalidatePath
للحصول على طريقة أكثر دقة لإعادة التحقق، يمكنك إبطال الصفحات عند الطلب باستخدام دالة revalidatePath
.
على سبيل المثال، سيتم استدعاء هذا الإجراء الخادم بعد إضافة منشور جديد. بغض النظر عن كيفية استرداد البيانات في مكون الخادم الخاص بك، سواء باستخدام fetch
أو الاتصال بقاعدة بيانات، سيؤدي هذا إلى مسح ذاكرة التخزين المؤقت للمسار بالكامل والسماح لمكون الخادم باسترداد بيانات جديدة.
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost() {
// إبطال مسار /posts في ذاكرة التخزين المؤقت
revalidatePath('/posts')
}
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost() {
// إبطال مسار /posts في ذاكرة التخزين المؤقت
revalidatePath('/posts')
}
عرض تجريبي واستكشف الكود المصدري.
إعادة التحقق عند الطلب باستخدام revalidateTag
لمعظم حالات الاستخدام، يُفضل إبطال المسارات بالكامل. إذا كنت بحاجة إلى تحكم أكثر دقة، يمكنك استخدام دالة revalidateTag
. على سبيل المثال، يمكنك وضع علامة على استدعاءات fetch
الفردية:
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog', {
next: { tags: ['posts'] },
})
const posts = await data.json()
// ...
}
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog', {
next: { tags: ['posts'] },
})
const posts = await data.json()
// ...
}
إذا كنت تستخدم ORM أو تتصل بقاعدة بيانات، يمكنك استخدام unstable_cache
:
import { unstable_cache } from 'next/cache'
import { db, posts } from '@/lib/db'
const getCachedPosts = unstable_cache(
async () => {
return await db.select().from(posts)
},
['posts'],
{ revalidate: 3600, tags: ['posts'] }
)
export default async function Page() {
const posts = getCachedPosts()
// ...
}
import { unstable_cache } from 'next/cache'
import { db, posts } from '@/lib/db'
const getCachedPosts = unstable_cache(
async () => {
return await db.select().from(posts)
},
['posts'],
{ revalidate: 3600, tags: ['posts'] }
)
export default async function Page() {
const posts = getCachedPosts()
// ...
}
يمكنك بعد ذلك استخدام revalidateTag
في إجراءات الخادم أو معالج المسار:
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost() {
// إبطال جميع البيانات الموسومة بـ 'posts' في ذاكرة التخزين المؤقت
revalidateTag('posts')
}
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost() {
// إبطال جميع البيانات الموسومة بـ 'posts' في ذاكرة التخزين المؤقت
revalidateTag('posts')
}
التعامل مع الاستثناءات غير الملتقطة
إذا حدث خطأ أثناء محاولة إعادة تحقق البيانات، سيتم الاستمرار في تقديم آخر بيانات تم إنشاؤها بنجاح من ذاكرة التخزين المؤقت. في الطلب التالي، سيقوم Next.js بإعادة محاولة إعادة تحقق البيانات. تعلم المزيد عن التعامل مع الأخطاء.
تخصيص موقع ذاكرة التخزين المؤقت
يمكنك تكوين موقع ذاكرة التخزين المؤقت لـ Next.js إذا كنت تريد الاحتفاظ بالصفحات والبيانات المخزنة مؤقتًا في تخزين دائم، أو مشاركة ذاكرة التخزين المؤقت عبر عدة حاويات أو نسخ من تطبيق Next.js الخاص بك. تعلم المزيد.
استكشاف الأخطاء وإصلاحها
تصحيح البيانات المخزنة مؤقتًا في التطوير المحلي
إذا كنت تستخدم واجهة برمجة التطبيقات fetch
، يمكنك إضافة سجلات إضافية لفهم أي الطلبات مخزنة مؤقتًا أو غير مخزنة. تعلم المزيد عن خيار logging
.
module.exports = {
logging: {
fetches: {
fullUrl: true,
},
},
}
التحقق من سلوك الإنتاج الصحيح
للتحقق من أن صفحاتك مخزنة مؤقتًا ويتم إعادة التحقق منها بشكل صحيح في بيئة الإنتاج، يمكنك الاختبار محليًا عن طريق تشغيل next build
ثم next start
لتشغيل خادم Next.js للإنتاج.
هذا سيسمح لك باختبار سلوك التوليد التدريجي الثابت (ISR) كما يعمل في بيئة الإنتاج. لمزيد من التصحيح، أضف متغير البيئة التالي إلى ملف .env
الخاص بك:
NEXT_PRIVATE_DEBUG_CACHE=1
هذا سيجعل خادم Next.js يسجل في الكونسول عمليات الوصول والإخفاق في ذاكرة التخزين المؤقت لـ ISR. يمكنك فحص المخرجات لمعرفة الصفحات التي يتم توليدها أثناء next build
، وكذلك كيف يتم تحديث الصفحات عند الوصول إلى المسارات عند الطلب.
محاذير
- التوليد التدريجي الثابت (ISR) مدعوم فقط عند استخدام بيئة تشغيل Node.js (الافتراضية).
- التوليد التدريجي الثابت (ISR) غير مدعوم عند إنشاء تصدير ثابت.
- إذا كان لديك عدة طلبات
fetch
في مسار تم عرضه بشكل ثابت، ولكل منها ترددrevalidate
مختلف، سيتم استخدام أقل وقت لـ ISR. ومع ذلك، سيتم احترام تردداتrevalidate
هذه بواسطة ذاكرة التخزين المؤقت للبيانات. - إذا كان لأي من طلبات
fetch
المستخدمة في مسار وقتrevalidate
بقيمة0
، أوno-store
صريح، سيتم عرض المسار ديناميكيًا. - لن يتم تنفيذ Middleware لطلبات ISR عند الطلب، مما يعني أن أي إعادة كتابة للمسار أو منطق في Middleware لن يتم تطبيقه. تأكد من أنك تقوم بإعادة التحقق من المسار الدقيق. على سبيل المثال،
/post/1
بدلاً من/post-1
المعاد كتابتها.
دعم المنصات
خيار النشر | مدعوم |
---|---|
خادم Node.js | نعم |
حاوية Docker | نعم |
تصدير ثابت | لا |
المحولات | حسب المنصة |
تعلم كيفية تكوين ISR عند استضافة Next.js ذاتيًا.
سجل الإصدارات
الإصدار | التغييرات |
---|---|
v14.1.0 | cacheHandler المخصص أصبح مستقرًا. |
v13.0.0 | تم تقديم App Router. |
v12.2.0 | Pages Router: أصبح التوليد التدريجي الثابت عند الطلب (On-Demand ISR) مستقرًا |
v12.0.0 | Pages Router: تمت إضافة الاسترجاع التلقائي لـ ISR مع مراعاة الروبوتات. |
v9.5.0 | Pages Router: تم تقديم ISR المستقر. |