404 Not Found

404 Not Found


nginx

أوضاع التصيير SSR و CSR

اكتشف Charlie أن جميع صفحات MegaShop تستخدم SSR، مما يضع ضغطاً هائلاً على الخوادم—حيث يتم تصيير ملايين صفحات المنتجات مع كل طلب. محتوى الصفحة الرئيسية نادراً ما يتغير، لكنه يُعاد تصييره مع كل طلب. لوحة التحكم لا تحتاج SEO، لكنها تُصيَّر على الخادم. التصيير الهجين يتيح لكل صفحة اختيار الاستراتيجية المثلى: SSG للصفحة الرئيسية، ISR لقوائم المنتجات، SSR لصفحات التفاصيل، و CSR لمركز المستخدم.

1. ما ستتعلمه


2. قصة حقيقية لمهندس معمارية

(1) نقطة الألم: SSR على مستوى الموقع يُغرق الخادم

يتعامل MegaShop مع 5000 طلب في الثانية، جميعها عبر SSR. محتوى الصفحة الرئيسية يتغير مرة واحدة فقط يومياً، لكنه يُصيَّر مع كل طلب. قائمة المنتجات تُحدَّث كل ساعة، مما يؤدي إلى التصيير المتكرر لمليون صفحة تفاصيل منتج. استخدام وحدة المعالجة المركزية للخادم وصل إلى 90%، لذا يخطط Bob لإضافة 10 خوادم أخرى.

(2) حل التصيير الهجين

routeRules في Nuxt 3 يتيح لكل مسار امتلاك استراتيجية تصيير خاصة:

TYPESCRIPT
// nuxt.config.ts
routeRules: {
  '/': { prerender: true },        // الصفحة الرئيسية: بناء مرة واحدة
  '/products': { swr: 3600 },      // قائمة المنتجات: تخزين مؤقت لساعة
  '/products/**': { swr: 86400 },  // تفاصيل المنتج: تخزين مؤقت ليوم
  '/admin/**': { ssr: false }      // لوحة التحكم: العميل فقط
}

(3) الفوائد: انخفاض حمولة الخادم بنسبة 85%

بعد تطبيق التصيير الهجين، انخفضت طلبات SSR من 5000 في الثانية إلى 750 في الثانية، وانخفض عدد الخوادم من 10 إلى 3، وانخفضت التكلفة بنسبة 70%.


3. وضع تصيير routeRules

(1) شجرة قرار التصيير الهجين

100%
flowchart TB
    A[طلب الصفحة] --> B{تحتاج SEO؟}
    B -->|لا| C[CSR - ssr: false]
    B -->|نعم| D{المحتوى يتغير؟}
    D -->|أبداً| E[SSG - prerender: true]
    D -->|نادراً| F[ISR - swr: ثوانٍ]
    D -->|بشكل متكرر| G[SSR - الوضع الافتراضي]
    D -->|يختلف حسب المنطقة| H[ESR - تصيير الحافة]
    C --> I[لوحة التحكم / لوحة المعلومات / مركز المستخدم]
    E --> J[حول / قانوني / صفحة هبوط]
    F --> K[قائمة المنتجات / صفحات الفئات]
    G --> L[تفاصيل المنتج / نتائج البحث]
    H --> M[الصفحة الرئيسية العالمية / المحتوى الإقليمي]

(2) مرجع سريع لخيار routeRules

الخيار القيمة التأثير السيناريوهات المناسبة
ssr boolean مفتاح SSR false = CSR
csr boolean مفتاح CSR خيار قديم
swr number/string مدة تخزين ISR المؤقت (بالثواني) صفحات تُحدَّث دورياً
prerender boolean تصيير مسبق أثناء البناء صفحة ثابتة
hydrate boolean إرواء فقط، بدون تصيير تحسين خاص
redirect string إعادة توجيه 301/302 نقل URL
cors boolean نطاق مشترك مسار API
headers object رؤوس استجابة مخصصة تخزين مؤقت/أمان

(1) ▶ مثال: تكوين routeRules كامل

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // الصفحة الرئيسية: تصيير مسبق أثناء البناء
    '/': { prerender: true },

    // صفحات ثابتة
    '/about': { prerender: true },
    '/privacy': { prerender: true },

    // قائمة المنتجات: ISR مع تخزين مؤقت لساعة
    '/products': { swr: 3600 },

    // تفاصيل المنتج: ISR مع تخزين مؤقت لمدة 24 ساعة
    '/products/**': { swr: 86400 },

    // الفئات: ISR مع تخزين مؤقت لمدة 6 ساعات
    '/categories/**': { swr: 21600 },

    // لوحة التحكم: تصيير من جهة العميل فقط
    '/admin/**': { ssr: false },

    // صفحات المستخدم: من جهة العميل
    '/profile/**': { ssr: false },

    // API: رؤوس CORS
    '/api/**': { cors: true },

    // عمليات إعادة التوجيه
    '/shop/': { redirect: '/products/', redirectCode: 301 },

    // رؤوس مخصصة للأصول الثابتة
    '/_nuxt/**': { headers: { 'cache-control': 'max-age=31536000' } }
  }
})

الناتج:

TEXT
// تم التنفيذ بنجاح

4. ISR إعادة التصيير الثابت التزايدي

(1) سير عمل ISR

100%
sequenceDiagram
    participant U as المستخدم
    participant C as CDN/Cache
    participant S as خادم Nuxt
    participant D as قاعدة البيانات

    U->>C: GET /products/123
    C->>C: أصاب التخزين المؤقت؟ (ضمن فترة swr)
    C-->>U: HTML مخزّن مؤقتاً (فوري)
    
    Note over C,S: بعد انتهاء فترة swr
    U->>C: GET /products/123
    C->>C: التخزين المؤقت قديم
    C-->>U: HTML قديم (لا يزال سريعاً)
    C->>S: إعادة التحقق في الخلفية
    S->>D: جلب أحدث البيانات
    D-->>S: بيانات محدّثة
    S-->>C: HTML جديد
    Note over C: الطلب التالي يحصل على HTML جديد

(2) مقارنة بين ISR و SSR و SSG

البُعد SSR SSG (prerender) ISR (swr)
توقيت التصيير مع كل طلب أثناء البناء تحديث في الخلفية بعد انتهاء التخزين المؤقت
وقت الاستجابة 🟡 متوسط 🟢 الأسرع 🟢 سريع (إصابة التخزين المؤقت)
حداثة البيانات ✅ الأحدث ❌ ثابت وقت البناء ⚠️ أقصى تأخير = ثوانٍ swr
حمولة الخادم 🔴 عالية 🟢 الأقل 🟢 منخفضة
حالات الاستخدام بيانات آنية لا تتغير أبداً تحديثات مجدولة

(1) ▶ مثال: صفحة قائمة منتجات ISR

TYPESCRIPT
// nuxt.config.ts - تكوين ISR
export default defineNuxtConfig({
  routeRules: {
    // قائمة المنتجات: تقديم من التخزين المؤقت، إعادة التحقق كل 60 ثانية
    '/products': { swr: 60 },
    // تفاصيل المنتج: تخزين مؤقت لساعة
    '/products/**': { swr: 3600 }
  }
})

الناتج:

TEXT
// تم التنفيذ بنجاح

(2) ▶ مثال: إبطال تخزين ISR المؤقت برمجياً

TYPESCRIPT
// server/api/invalidate-cache.post.ts
export default defineEventHandler(async (event) => {
  const { path } = await readBody(event)

  // مسح المسار المُخزَّن مؤقتاً المحدد
  await useStorage('cache').removeItem(`nitro:routes:${path}`)

  return { message: `Cache invalidated for ${path}`, timestamp: Date.now() }
})

الناتج:

TEXT
// تم التنفيذ بنجاح

5. تصيير حافة ESR

(1) مبادئ تصيير الحافة

ESR (تصيير جانب الحافة) ينفذ التصيير في عُقد حافة CDN، ويسترجع المستخدمون HTML من أقرب عُقدة.

البُعد SSR المركزي ESR
موقع الخادم منطقة واحدة عُقد حافة عالمية
زمن الاستجابة يعتمد على المسافة الحد الأدنى (وصول محلي)
حالات الاستخدام مستخدمون في منطقة واحدة مستخدمون عالميون
إعدادات Nitro المسبقة node-server cloudflare-pages / vercel-edge

(1) ▶ مثال: تكوين نشر Vercel Edge

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'vercel-edge'
  },
  routeRules: {
    // الصفحة الرئيسية مصيَّرة عند الحافة للمستخدمين العالميين
    '/': { swr: 3600 },
    '/products/**': { swr: 86400 }
  }
})

الناتج:

TEXT
// تم التنفيذ بنجاح

6. استراتيجية التصيير الهجين لـ MegaShop

(1) تخطيط استراتيجية تصيير صفحات MegaShop

الصفحة URL الاستراتيجية SWR السبب
الصفحة الرئيسية / SSG - محتوى مستقر، يُصيَّر أثناء البناء
صفحة حول /about SSG - تكاد لا تتغير
قائمة المنتجات /products ISR 3600 المنتجات تُحدَّث كل ساعة
صفحة الفئات /categories/** ISR 21600 تُحدَّث يومياً
تفاصيل المنتج /products/** ISR 86400 تُحدَّث يومياً
نتائج البحث /search SSR - استعلام آني
سلة التسوق /cart CSR - للأعضاء فقط
مركز المستخدم /profile/** CSR - SEO غير مطلوب
لوحة التحكم /admin/** CSR - SEO غير مطلوب
API /api/** - - API بيانات فقط

(1) ▶ مثال: routeRules كامل لـ MegaShop

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  ssr: true,

  routeRules: {
    // SSG: تصيير مسبق أثناء البناء
    '/': { prerender: true },
    '/about': { prerender: true },
    '/privacy': { prerender: true },
    '/contact': { prerender: true },

    // ISR: تخزين مؤقت مع إعادة التحقق
    '/products': { swr: 3600 },           // ساعة واحدة
    '/categories/**': { swr: 21600 },     // 6 ساعات
    '/products/**': { swr: 86400 },       // 24 ساعة

    // SSR: تصيير آني
    '/search': { swr: 0 },

    // CSR: من جهة العميل فقط
    '/cart': { ssr: false },
    '/checkout/**': { ssr: false },
    '/profile/**': { ssr: false },
    '/admin/**': { ssr: false },

    // API
    '/api/**': { cors: true },

    // أصول ثابتة: تخزين مؤقت طويل
    '/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } },
    '/images/**': { headers: { 'cache-control': 'public, max-age=86400' } }
  }
})

الناتج:

TEXT
// تم التنفيذ بنجاح

(2) حل انتهاء تخزين ISR المؤقت لصفحات المنتجات بعدد مليون صفحة

الحدث سياسة الانتهاء التنفيذ
تحديث سعر المنتج إبطال صفحة المنتج المتأثرة useStorage('cache').removeItem()
منتجات جديدة إبطال قائمة المنتجات إبطال دفعي لتخزين /products المؤقت
تغييرات الفئات إبطال صفحات الفئات إبطال /categories/xxx
تخفيض على مستوى الموقع مسح جميع صفحات المنتجات مسح التخزين المؤقت بالكامل
تغييرات المخزون إبطال المنتجات المتأثرة تشغيل عبر Webhook

7. مثال شامل: التحقق من أوضاع تصيير MegaShop

VUE
<!-- pages/admin/dashboard.vue - وضع CSR -->
<template>
  <div>
    <h1>Admin Dashboard</h1>
    <p>Rendering mode: Client-Side Only</p>
    <p>Current time: {{ currentTime }}</p>
  </div>
</template>

<script setup lang="ts">
// CSR: هذه الصفحة غير مصيَّرة على الخادم
definePageMeta({ ssr: false, layout: 'sidebar' })

const currentTime = ref(new Date().toISOString())
onMounted(() => {
  setInterval(() => {
    currentTime.value = new Date().toISOString()
  }, 1000)
})
</script>
VUE
<!-- pages/products/[id].vue - وضع ISR -->
<template>
  <div v-if="product">
    <h1>{{ product.name }}</h1>
    <p>${{ product.price }} USD</p>
    <p>Cache: revalidated every 24 hours</p>
  </div>
</template>

<script setup lang="ts">
// ISR: مخزّن مؤقتاً لمدة 24 ساعة عبر routeRules swr: 86400
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
</script>

❓ أسئلة شائعة

س ما وحدة قياس swr؟
ج الثواني. swr: 60 يشير إلى تخزين مؤقت لمدة 60 ثانية؛ بعد انتهائه، الطلب التالي يشغل تحديثاً في الخلفية، لكن الطلب الحالي يُرجع بيانات التخزين المؤقت القديمة.
س هل يمكن استخدام prerender و SWR معاً؟
ج نعم. { prerender: true, swr: 3600 } يشير إلى تصيير مسبق أثناء البناء، ثم تحديث باستخدام استراتيجية تخزين ISR المؤقت.
س أين يُخزَّن تخزين ISR المؤقت؟
ج يعتمد على إعداد Nitro المسبق. إعداد Node.js يخزنه في الذاكرة أو نظام الملفات؛ إعداد Vercel يستخدم Vercel KV؛ و Cloudflare يستخدم تخزين KV.
س ماذا تُرجع صفحة CSR أثناء SSR؟
ج تُرجع قالب HTML فارغ (يحتوي فقط على div id="__nuxt" وحزمة JS)؛ جميع المحتوى يُصيَّر على جانب العميل.
س كيف أتحقق من وضع التصيير المستخدم في الصفحة الحالية؟
ج عرض المصدر (Ctrl+U)—إذا كان هناك محتوى، فهو SSR/SSG/ISR؛ إذا كان فارغاً، فهو CSR. رأس الاستجابة x-nuxt-render-mode يشير أيضاً إلى وضع التصيير.
س هل سيملأ تخزين ISR المؤقت لملايين صفحات المنتجات مساحة التخزين؟
ج المنتجات الشائعة تبقى في التخزين المؤقت بشكل طبيعي، بينما الأقل شعبية تُزال تلقائياً بعد انتهاء صلاحيتها. لا حاجة لتخزين جميع المليون صفحة مسبقاً؛ فقط تلك التي تم الوصول إليها تُخزَّن مؤقتاً.

📖 ملخص


📝 تمارين

  1. تمرين أساسي (الصعوبة: ⭐): كوِّن routeRules لتمكين التصيير المسبق للصفحة الرئيسية و CSR لصفحة لوحة التحكم، ثم تحقق من الفروق في مخرجات "عرض المصدر" بين الوضعين.
  2. تمرين متقدم (الصعوبة: ⭐⭐): كوِّن ISR (swr: 60) لقائمة المنتجات، وبعد 60 ثانية، حدِّث الصفحة لترى ما إذا كانت البيانات قد تحدثت.
  3. تحدٍ (الصعوبة: ⭐⭐⭐): نفِّذ واجهة API لإبطال تخزين ISR المؤقت. عند تحديث بيانات المنتج، استدعِ /api/invalidate-cache لإبطال التخزين المؤقت المقابل، وتحقق أن الطلب التالي يحصل على البيانات الجديدة.

---|

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%