ISR في النطاق الكبير: تشغيل 25,000+ صفحة مع Incremental Static Regeneration على Vercel

في العام الماضي، أطلقنا موقع Next.js يحتوي على أكثر من 25,000 صفحة تم إنشاؤها بشكل ثابت على Vercel. صفحات المنتجات، مشاركات المدونة، صفحات الهبوط للمواقع، مرشحات الفئات الديناميكية -- كل شيء. وعد Incremental Static Regeneration يبدو مغريًا: احصل على سرعة المواقع الثابتة مع طزاجة محتوى معروض من الخادم. والصراحة؟ في الغالب يحقق ذلك. لكن مع 25,000+ صفحة، يتصرف ISR بشكل مختلف عما يحدث على موقعك التسويقي بـ 50 صفحة. حالات الحافة تصبح حالاتك الرئيسية. التكاليف تزحف. مشاكل cache invalidation التي بدت نظرية في الوثائق تصبح حقيقية جدًا.

هذا هو المقال الذي أتمنى أن كان موجودًا قبل أن نبدأ. كل شيء هنا يأتي من تجربة الإنتاج -- مقاييس حقيقية، مفاجآت فواتير حقيقية، وقرارات معمارية حقيقية اتخذناها (وأحيانًا ندمنا عليها).

ISR at Scale: Running 25,000+ Pages with Incremental Static Regeneration on Vercel

جدول المحتويات

ما الذي يفعله ISR بالفعل تحت الغطاء

قبل أن نتعمق في مشاكل النطاق، دعنا نتأكد من أننا على نفس الصفحة حول ما يفعله ISR. عندما تقوم بتعيين revalidate: 60 في صفحة Next.js، إليك التدفق الفعلي:

  1. الطلب الأول بعد الإطلاق: إذا تم عرض الصفحة مسبقًا وقت البناء، يقدمها Vercel من ذاكرة التخزين المؤقت للحافة. إذا لم يكن الأمر كذلك (أرجعت fallback: 'blocking' أو استخدمت dynamicParams: true في App Router)، يتم عرضها من جانب الخادم، وتخزين النتيجة مؤقتًا، ثم تقديمها.

  2. الطلبات اللاحقة ضمن نافذة إعادة التحقق: يتم تقديمها من الذاكرة المؤقتة. سريع. بدون حوسبة.

  3. الطلب الأول بعد انتهاء نافذة إعادة التحقق: يتم تقديم الصفحة القديمة فوراً (هذا هو جزء "stale-while-revalidate")، وتُشغل إعادة إنشاء الخلفية. الزائر التالي يحصل على الصفحة الطازجة.

هذا مفهوم بسيط من الناحية النظرية. لكن مع 25,000 صفحة، يصبح خطوة إعادة الإنشاء في الخلفية عبارة عن فيضان من البيانات.

// App Router (Next.js 14/15)
export const revalidate = 60; // ثواني

export async function generateStaticParams() {
  // مع 25k صفحة، ربما لن تريد إرجاع كل منها هنا
  const topPages = await getTop500Pages();
  return topPages.map((page) => ({ slug: page.slug }));
}

export default async function ProductPage({ params }: { params: { slug: string } }) {
  const product = await getProduct(params.slug);
  return <ProductTemplate product={product} />;
}

مقايضة Stale-While-Revalidate

الشيء الذي يربك الناس: ISR يقدم دائمًا محتوى قديمًا للطلب الذي يشغل إعادة الإنشاء. هذه ميزة وليست خاصية سيئة -- فهذا يعني أن لا زائر ينتظر أبدًا للحصول على عرض. لكن هذا يعني أيضًا أن محتواك يتأخر دائمًا بطلب واحد على الأقل. لموقع 25,000 صفحة حيث تزار بعض الصفحات مرة واحدة فقط في الأسبوع، قد تعني تلك الكلمة "خلف بطلب واحد" أن شخصًا ما يرى محتوى قديمًا جدًا بعد انتهاء نافذة إعادة التحقق، لأن لم يزر أحد لتشغيل إعادة الإنشاء.

لماذا تغيّر 25,000 صفحة كل شيء

في نطاق صغير، ISR سحر بشكل أساسي. في نطاق كبير، تتغير ثلاثة أشياء:

أوقات البناء تصبح اختناقًا

إذا حاولت عرض جميع 25,000 صفحة مسبقًا وقت البناء، فأنت تنظر إلى أوقات بناء ستجعلك تشك في اختياراتك في الحياة. تحتاج كل صفحة إلى جلب بيانات، ورسم React إلى HTML، وتوليد الأصول الثابتة. حتى في 200ms لكل صفحة (وهذا متفائل إذا كنت تضرب API تحويل محتوى)، هذا 5,000 ثانية -- أكثر من 83 دقيقة. خطة Vercel Pro لديها حد انتظار بناء بـ 45 دقيقة. Enterprise يحصل على أكثر، لكنك لا تزال تحرق ائتمانات الحوسبة.

Cache Invalidation تصبح مشكلة حقيقية

مع 25,000 صفحة، لا يمكنك فقط "إعادة بناء كل شيء" عند تغيير المحتوى. تحتاج إلى بطل غير دقيق. تساعد واجهات برمجة التطبيقات revalidatePath() و revalidateTag() من Vercel، لكن لديها خصائصها الخاصة في النطاق الكبير التي سنغطيها.

ارتفاع حمل إعادة الإنشاء في الخلفية

تخيل 5,000 صفحة جميعها تحتوي على revalidate: 60 وجميعها تحصل على حركة المرور بشكل متزامن. هذا 5,000 استدعاء دالة بدون خادم يحدث في الخلفية كل دقيقة. واجهة برمجة تطبيقات CMS الخاصة بك من الأفضل أن تكون قادرة على التعامل مع ذلك.

ISR at Scale: Running 25,000+ Pages with Incremental Static Regeneration on Vercel - architecture

استراتيجية البناء: ما يجب عرضه مسبقًا مقابل ما يتم تأجيله

هذا هو قرار معماري واحد الأكثر أهمية لمواقع ISR الكبيرة. إليك الإطار الذي نستخدمه:

فئة الصفحة العدد (حالتنا) الاستراتيجية السبب
الصفحات عالية حركة المرور (أفضل 500) 500 عرض مسبق وقت البناء يتم الوصول إليها فور الإطلاق. بدون عقوبة بدء بارد.
صفحات حركة المرور المتوسطة 4,500 تأجيل مع fallback: 'blocking' انتظار الزائر الأول ~300ms، ثم يتم تخزينها مؤقتًا. مقبول.
صفحات الذيل الطويل 20,000 تأجيل مع fallback: 'blocking' معظمها لن يتم زيارته لساعات/أيام بعد الإطلاق. لا معنى للعرض المسبق.

الرؤية الرئيسية: لا تعرض مسبقًا الصفحات التي لن يزورها أحد في الساعة الأولى بعد الإطلاق. أنت تهدر دقائق البناء والمال.

// generateStaticParams - أرجع فقط صفحاتك عالية حركة المرور
export async function generateStaticParams() {
  // نستخدم بيانات التحليلات لتحديد الصفحات الأعلى
  const topPages = await fetch('https://api.example.com/pages/top?limit=500', {
    headers: { Authorization: `Bearer ${process.env.CMS_TOKEN}` },
  }).then(r => r.json());

  return topPages.map((page: { slug: string }) => ({
    slug: page.slug,
  }));
}

مع هذا النهج، انتقلت عمليات البناء من انتهاء المهلة الزمنية إلى الانتهاء في حوالي 8 دقائق. هذا اختلاف ضخم. كتبنا عن استراتيجيات تحسين مماثلة في سياق عمل تطوير Next.js الخاص بنا -- تنطبق المبادئ على نطاق واسع.

إعداد `dynamicParams` مهم

في App Router، إعداد dynamicParams = true (الافتراضي) يعني أن الصفحات غير المعادة من generateStaticParams سيتم عرضها عند الطلب وتخزينها مؤقتًا. إعداده إلى false يعيد 404 لأي صفحة لم تُعرض مسبقًا. لموقع 25,000 صفحة، تريد بالتأكيد true.

export const dynamicParams = true; // السماح بالعرض عند الطلب للصفحات غير الموجودة في generateStaticParams

أنماط إعادة التحقق التي تعمل فعلاً

إعادة التحقق القائمة على الوقت

الأسلوب الأبسط. عيّن revalidate إلى عدد من الثواني. لكن أي عدد؟

هنا ما وصلنا إليه بعد أشهر من التوليف:

نوع المحتوى فترة إعادة التحقق السبب
أسعار المنتجات 60 ثانية تتغير الأسعار بشكل متكرر، يلاحظ العملاء الأسعار القديمة
وصفات المنتجات 3600 ثانية (ساعة واحدة) نادرا ما تتغير، غير حساسة للوقت
مشاركات المدونة 86400 ثانية (24 ساعة) لا تتغير تقريبًا بعد النشر
صفحات الفئة/القوائم 300 ثانية (5 دقائق) تظهر منتجات جديدة، لكن التأخير البسيط موافق
صفحات المواقع 86400 ثانية (24 ساعة) معلومات العنوان بالكاد تتغير

الخطأ الذي ارتكبناه في البداية: تعيين كل شيء إلى 60 ثانية. هذا سحق واجهة برمجة تطبيقات CMS الخاصة بنا (Contentful، في حالتنا) بطلبات إعادة الإنشاء وضربنا حدود المعدل خلال طفرات حركة المرور.

إعادة التحقق عند الطلب

هذا هو النهج الأفضل لمعظم تحديثات المحتوى. بدلاً من الاستجواب مع إعادة التحقق المستندة إلى الوقت، فأنت تشغل إعادة الإنشاء عند تغيير المحتوى فعلاً:

// app/api/revalidate/route.ts
import { revalidateTag, revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidation-secret');
  
  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
  }

  const body = await request.json();
  
  // إعادة التحقق المستندة إلى الوسم -- هذا هو الطريق
  if (body.tag) {
    revalidateTag(body.tag);
    return NextResponse.json({ revalidated: true, tag: body.tag });
  }

  // إعادة التحقق المستندة إلى المسار كخطة احتياطية
  if (body.path) {
    revalidatePath(body.path);
    return NextResponse.json({ revalidated: true, path: body.path });
  }

  return NextResponse.json({ error: 'No tag or path provided' }, { status: 400 });
}

ثم قم بإعداد webhook في CMS الخاص بك لضرب نقطة النهاية هذه كلما تم نشر محتوى. نقترنها بإعادة تحقق مستندة إلى الوقت أطول (مثل 24 ساعة) كشبكة أمان.

إعادة التحقق المستندة إلى الوسم على النطاق الكبير

هنا يتألق Next.js 14+ حقًا للمواقع الكبيرة. يمكنك وسم طلبات الجلب الخاصة بك والتحقق من صحتها حسب الوسم:

async function getProduct(slug: string) {
  const res = await fetch(`https://api.cms.com/products/${slug}`, {
    next: { 
      tags: [`product-${slug}`, 'products', 'all-content'],
      revalidate: 86400 // شبكة أمان لمدة 24 ساعة
    },
  });
  return res.json();
}

الآن عندما يتم تحديث منتج واحد، استدعِ revalidateTag('product-blue-widget') ويتم إعادة إنشاء هذه الصفحة فقط. عندما تقوم بتحديث سعر جماعي، استدعِ revalidateTag('products') وجميع صفحات المنتجات تعاد إنشاؤها عند الزيارة التالية.

المحاذير: استدعاء revalidateTag('products') على موقع يحتوي على 25,000 صفحة منتج لا يعيد إنشاء جميعها فورًا. إنه يوسمها جميعًا بأنها قديمة. يعاد إنشاؤها عند الزيارة التالية. هذا مهم -- فهذا يعني أن بعض الصفحات قد لا تُحدث فعليًا لأيام إذا كان لديها حركة مرور منخفضة.

مثالب وحدود خاصة بـ Vercel

كنا نقوم بتشغيل هذا على Vercel منذ أوائل 2024. فيما يلي الأشياء التي لا تؤكد الوثائق بشكل كافٍ:

تخزين ISR Cache

تخزن Vercel صفحات ISR في شبكة Edge الخاصة بهم. اعتبارًا من 2025، لـ Vercel Data Cache بعض الحدود التي يجب أن تكون على دراية بها:

  • خطة Pro: ذاكرة التخزين المؤقت المدمجة ISR سخية، لكن هناك تكلفة لقراءة/كتابة ذاكرة التخزين المؤقت بحجم كبير جدًا
  • Enterprise: حدود مخصصة، لكن أنت تدفع مقابل ذلك
  • إدخالات ذاكرة التخزين المؤقت لا تعيش إلى الأبد: حتى مع revalidate: false، يمكن لـ Vercel إزالة إدخالات ذاكرة التخزين المؤقت التي لم يتم الوصول إليها مؤخرًا. لقد شهدنا اختفاء صفحات من ذاكرة التخزين المؤقت بعد حوالي 30 يومًا من عدم وجود حركة مرور على خطة Pro.

مدة دالة بدون خادم

يتم تشغيل إعادة الإنشاء في الخلفية كدالة بدون خادم. على Vercel Pro، المهلة الزمنية الافتراضية هي 60 ثانية (يمكنك التكوين حتى 300 ثانية). إذا استغرقت صفحتك وقتًا أطول من ذلك للعرض الجديد -- على سبيل المثال، لأن CMS الخاص بك بطيء أو تقوم بمعالجة صور ثقيلة -- فإن إعادة الإنشاء تفشل بصمت والصفحة القديمة تستمر في التقديم.

اصطدمنا بهذا مع صفحات جلبت البيانات من ثلاث واجهات برمجة تطبيقات مختلفة. الإصلاح كان إضافة طبقة تخزين مؤقت (Redis عبر Upstash) بين تطبيق Next.js الخاص بنا وواجهة برمجة التطبيقات الأبطأ.

حدود إعادة الإنشاء المتزامن

لا تنشر Vercel أرقامًا صارمة حول هذا، لكننا لاحظنا الاختناق عندما تم تشغيل أكثر من ~1,000 إعادة إنشاء ISR بشكل متزامن (على سبيل المثال، بعد استدعاء revalidateTag على وسم يستخدم على نطاق واسع). تصطف إعادات الإنشاء وتعالج على مدى عدة دقائق بدلاً من كل شيء في نفس الوقت. خطط لهذا.

بدايات باردة

الصفحات التي لم يتم زيارتها منذ فترة (وتم إزالتها من ذاكرة التخزين المؤقت للحافة) ستواجه بداية باردة عند الزيارة التالية. في معايير الأداء لدينا:

  • ضرب ذاكرة التخزين المؤقت الدافئة: 15-40ms TTFB
  • إعادة التحقق القديمة (تقدم من الذاكرة المؤقتة): 15-40ms TTFB (نفسه، لأن القديم يُقدم)
  • إعادة الإنشاء البارد (بدون ذاكرة تخزين مؤقت، يحجب): 400-1200ms TTFB اعتمادًا على أوقات استجابة واجهة برمجة التطبيقات

التكاليف الحقيقية للإنتاج على النطاق الكبير

دعونا نتحدث عن المال. هنا حيث يتفاجأ الناس.

موقعنا بـ 25,000 صفحة على Vercel Pro ($20/شهر الأساس) مع ISR:

مكون التكلفة شهريًا ملاحظات
اشتراك Vercel Pro $20 خطة الأساس
تنفيذ دالة بدون خادم $180-$340 يختلف حسب حركة المرور. تحسب تعويضات ISR كاستدعاءات دالة.
نطاق الحافة $90-$150 25k صفحة مع الصور تراكم
Vercel Data Cache $40-$80 قراءة/كتابة ذاكرة التخزين المؤقت لـ ISR
Vercel الإجمالي $330-$590/mo يعتمد على حركة المرور الشهرية
Contentful (CMS) $489/mo خطتهم Team. استدعاءات واجهة برمجية التطبيقات من إعادة الإنشاء ISR دفعتنا فوق المستوى المجاني بسرعة.
Upstash Redis (تخزين مؤقت) $30/mo أُضيفت لتقليل استدعاءات واجهة برمجية التطبيقات CMS
المجموع الكلي $849-$1,109/mo لموقع يخدم ~2M pageviews/شهر

هل هذا مكلف؟ مقارنة بإعداد خادم تقليدي، فهو تنافسي. مقارنة بموقع ثابت على CDN، فهو باهظ الثمن. استدعاءات دالة إعادة الإنشاء ISR هي أكبر تكلفة متغيرة -- في كل مرة يتم إعادة إنشاء صفحة، هذه دالة بدون خادم تعمل لمدة 1-5 ثواني.

استكشفنا مع العملاء أساليب مستندة إلى Astro للمواقع التي تحتوي على محتوى كثيف حيث تبدأ تكاليف ISR بتجاوز فوائدها. بالنسبة للمواقع حيث يتغير المحتوى بشكل نادر، يمكن للبناء الثابت الكامل مع Astro أن يكون أرخص بشكل كبير في الاستضافة.

المراقبة وتصحيح الأخطاء في ISR في الإنتاج

فشل ISR يكون صامتًا بشكل افتراضي. الصفحة القديمة تستمر في التقديم، وقد لا تعرف أن إعادة الإنشاء قد تفشل لأيام. إليك إعداد المراقبة لدينا:

تسجيل إعادة الإنشاء المخصص

// lib/with-regeneration-logging.ts
export async function fetchWithLogging(
  url: string,
  options: RequestInit & { next?: { tags?: string[]; revalidate?: number } }
) {
  const start = Date.now();
  try {
    const res = await fetch(url, options);
    const duration = Date.now() - start;
    
    // سجل إلى خدمة المراقبة الخاصة بك
    if (duration > 5000) {
      console.warn(`[ISR] Slow fetch: ${url} took ${duration}ms`);
      // أرسل إلى Datadog/Sentry/إلخ.
    }
    
    return res;
  } catch (error) {
    console.error(`[ISR] Fetch failed: ${url}`, error);
    // هذا حرج -- إذا فشل الجلب، إعادة الإنشاء تفشل
    throw error;
  }
}

أدوات Vercel المدمجة

يعرض لوحة معلومات Vercel نسب ضرب ذاكرة التخزين المؤقت ISR وعدد عمليات إعادة الإنشاء. في علامة التبويب Analytics، ابحث عن:

  • حالة Cache في سجلات الدالة: HIT، MISS، STALE
  • مدة إعادة الإنشاء ISR في مقاييس دالة بدون خادم
  • معدلات الخطأ على طرق ISR الخاصة بك

رأس `x-vercel-cache`

كل رد من Vercel يتضمن هذا الرأس:

  • HIT -- يقدم من ذاكرة التخزين المؤقت للحافة، طازج
  • STALE -- يقدم من ذاكرة التخزين المؤقت للحافة، إعادة إنشاء مشغلة في الخلفية
  • MISS -- لا توجد في الذاكرة المؤقتة، تُعرض عند الطلب

قمنا بإعداد مراقب بسيط يفحص 100 صفحة عشوائية كل ساعة وينبه إذا أعاد أكثر من 10% MISS -- سيشير ذلك إلى مشاكل في إزالة الذاكرة المؤقتة.

قرارات معمارية: ISR مقابل البدائل

بعد تشغيل ISR في هذا النطاق لأكثر من سنة، إليك رأيي الصريح حول متى يتم استخدامه ومتى لا:

استخدم ISR عندما:

  • لديك 5,000-100,000 صفحة تتغير بترددات مختلفة
  • طزاجة المحتوى تُقاس بالدقائق (وليس الثواني) مقبولة
  • أنت بالفعل ملتزم بـ Next.js
  • يفهم فريقك عدم استقرار الذاكرة المؤقتة (إنها ليست معرفة اختيارية بهذا النطاق)

ضع في اعتبارك البدائل عندما:

  • تحتاج إلى محتوى فوري (استخدم SSR أو جلب من جانب العميل بدلاً من ذلك)
  • موقعك نادرًا ما يتغير (عمليات البناء الثابتة الكاملة أبسط وأرخص)
  • لديك 500,000+ صفحة (يبدأ ISR بالإرهاق بعدد صفحات كبير جدًا -- ضع في اعتبارك نهج البناء الموزع)
  • التكلفة هي الشاغل الأساسي (Next.js الموجودة ذاتيًا مع CDN الخاص بك يمكن أن تكون أرخص بنسبة 60-70%)

للعملاء الذين لديهم بنى محتوى معقدة، غالبًا ما نوصي بإعداد CMS بدون رأس يمنحك المرونة للتبديل بين ISR و SSR والثابت الكامل حسب نوع المحتوى.

النهج الهجين الذي نستخدمه فعليًا

نحن لا نستخدم ISR لكل شيء على موقعنا بـ 25k صفحة. إليك التفصيل:

  • ISR: صفحات المنتجات، صفحات الفئات، صفحات المواقع (22,000 صفحة)
  • SSR: نتائج البحث، لوحة معلومات المستخدم، عربة التسوق
  • ثابت: حول، اتصل، صفحات قانونية (تم إنشاؤها وقت البناء، بدون إعادة تحقق)
  • جانب العميل: عدد المخزون الفعلي، التسعير المخصص للمستخدم

قلل هذا النهج الهجين تكاليف دالة بدون خادم لدينا بحوالي 40% مقارنة بإستراتيجية "ISR كل شيء" الأولية لدينا.

معايير الأداء من نشرتنا

فيما يلي أرقام حقيقية من نشرتنا الإنتاجية، تم قياسها على مدار Q1 2025:

مقياس ضرب ذاكرة ISR Cache فشل ذاكرة ISR Cache (يحجب) SSR الكامل (بدون Cache)
TTFB (p50) 22ms 480ms 620ms
TTFB (p95) 58ms 1,100ms 1,450ms
TTFB (p99) 120ms 2,800ms 3,200ms
LCP (p50) 1.1s 1.8s 2.2s
CLS 0.02 0.02 0.05
معدل مرور Core Web Vitals 96% 78% 64%

الفرق بين ضرب ذاكرة التخزين المؤقت وفشل حاد. هذا هو السبب في أن استراتيجية العرض المسبق الخاصة بك مهمة جدًا -- تريد صفحاتك عالية حركة المرور لتكون دافئة دائمًا.

اكتشاف مثير للاهتمام: تحسنت درجات Core Web Vitals الخاصة بنا بنسبة 12% عندما انتقلنا من revalidate: 60 إلى revalidate: 3600 على محتوى قليل التغيير. كان عدد إعادات الإنشاء أقل، مما عني ضربات ذاكرة تخزين مؤقت أكثر اتساقًا، مما عني أداء أكثر اتساقًا.

الأسئلة الشائعة

كم عدد الصفحات التي يمكن لـ ISR التعامل معها على Vercel قبل أن تتدهور الأداء؟ قمنا بتشغيل 25,000 صفحة بدون مشاكل كبيرة، وسمعت عن نشرات مع 100,000+ صفحة تعمل بشكل جيد. الاختناق ليس عدد الصفحات في الذاكرة المؤقتة -- إنها معدل إعادات الإنشاء المتزامنة. إذا كانت لديك 50,000 صفحة جميعها مع revalidate: 60، ستواجه مشاكل. نشر فترات إعادة التحقق الخاصة بك بناءً على تكرار تغيير المحتوى وستكون بخير.

هل ISR أكثر تكلفة من SSR على Vercel؟ بشكل عام، ISR أرخص بشكل ملحوظ من SSR لنفس حجم حركة المرور. مع ISR، معظم الطلبات يتم تقديمها من ذاكرة التخزين المؤقت للحافة (حوسبة مجانية بشكل أساسي). مع SSR، كل طلب يشغل دالة بدون خادم. لموقعنا بـ 2M pageviews/شهر، كانت استدعاءات دالة ISR حوالي 15% مما كان سيكون عليه SSR الكامل.

ماذا يحدث عندما تفشل إعادة إنشاء ISR؟ تستمر النسخة القديمة في التقديم. هذه ميزة وخطر في نفس الوقت. المستخدمون لا يرون أخطاء، لكنهم قد يرون محتوى قديمًا. كان لدينا حالات حيث كان انقطاع واجهة برمجية تطبيقات CMS يعني أن الصفحات كانت تخدم محتوى بعمر 6 ساعات قبل أن يلاحظ أحد. قم بإعداد المراقبة.

هل يمكنني استخدام ISR مع Next.js App Router؟ نعم، وهو أنظف فعليًا في App Router. تستخدم export const revalidate = 60 على مستوى الصفحة أو التخطيط، و next: { revalidate, tags } في استدعاءات الجلب الخاصة بك. تحل دالة generateStaticParams محل getStaticPaths. كل ما وصفناه في هذا المقال يعمل مع Pages Router و App Router، على الرغم من أن بناء جملة App Router هو ما نوصي به للمشاريع الجديدة في 2025.

كيفية التعامل مع ISR مع معاملات الاستعلام الديناميكية؟ ISR يخزن مؤقتًا فقط بناءً على مسار عنوان URL، وليس معاملات الاستعلام. إذا كنت بحاجة إلى نسخ مخزنة مؤقتة مختلفة لـ ?color=red مقابل ?color=blue، فأنت بحاجة إلى استخدام قطاعات مسار فعلية (/product/widget/red بدلاً من /product/widget?color=red) أو التعامل مع الاختلاف من جانب العميل. هذا فاجأنا مع تنفيذ الترشيح لدينا.

هل إعادة التحقق عند الطلب موثوقة على النطاق الكبير؟ في الغالب. لقد شهدنا تأخيرات عرضية بـ 10-30 ثانية بين استدعاء revalidateTag() والذاكرة المؤقتة فعليًا يتم إلغاء التحقق منها عبر جميع مواقع الحافة. بالنسبة لـ 99% من حالات الاستخدام هذا جيد. إذا كنت بحاجة إلى إلغاء بطلان عام فوري، فقد تحتاج إلى إضافة معاملات تجنب ذاكرة التخزين المؤقت أو استخدام SSR لتلك الصفحات المحددة.

هل يجب أن أستضيف ذاتيًا Next.js بدلاً من استخدام Vercel لمواقع ISR الكبيرة؟ يعتمد على فريقك. الاستضافة الذاتية (على AWS، على سبيل المثال) تمنحك سيطرة أكثر على سلوك التخزين المؤقت ويمكن أن تكون أرخص بـ 50-70% على النطاق الكبير. لكنك مسؤول عن إعداد إلغاء تحقق ذاكرة التخزين المؤقت CDN وإدارة خط أنابيب البناء والتعامل مع التوزيع الحافة بنفسك. لقد رأينا فرقًا تقضي شهورًا في تكرار ما توفره Vercel خارج الصندوق. إذا كنت تريد استكشاف الخيارات، تواصل معنا -- لقد فعلنا كلاهما.

ما هو أفضل CMS لموقع ISR بـ 25,000+ صفحة؟ استخدمنا Contentful و Sanity و Hygraph على هذا النطاق. يتعامل Contentful مع إعادة التحقق المستندة إلى webhook بشكل جيد لكن حدود المعدل يمكن أن تكون مشكلة (خطط للتخزين المؤقت). اشتراكات GROQ من Sanity رائعة للوعي الفعلي بتغييرات المحتوى. نظام webhook الخاص بـ Hygraph متين. المتطلب الرئيسي هو تسليم webhook موثوق وواجهة برمجية تطبيقات يمكنها التعامل مع حركة المرور المتفجرة من عواصف إعادة الإنشاء. راجع قدرات تطوير headless CMS الخاصة بنا للحصول على توصيات أكثر تحديدًا بناءً على نموذج المحتوى الخاص بك.