404 Not Found

404 Not Found


nginx

تحسين الأداء

أصبح MegaShop متاحاً الآن، لكن درجته في Lighthouse هي 45 فقط—يستغرق 4.5 ثانية لتحميل الشاشة الأولى، والصور غير محسّنة، وحزمة JS كبيرة جداً. يحتاج Charlie إلى درجة Lighthouse تتجاوز 90 وLCP أقل من ثانيتين للشاشة الأولى للبقاء تنافسياً.

1. ما ستتعلمه


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

(1) نقطة الألم: درجة Lighthouse 45، 4.5 ثانية حتى أول رسم للمحتوى

فتحت Alice موقع MegaShop على هاتفها واستغرق ظهور المنتجات 4.5 ثانية. شغّل Charlie تدقيق Lighthouse ووجد أن حزمة JS بحجم 2.8 ميغابايت، وجميع الصور بصيغة PNG غير مضغوطة، ولا توجد عناوين تخزين مؤقت، وكود 50 مكوّناً يُحمّل على الشاشة الأولى.

(2) حلول تحسين الأداء في Nuxt 3

يتضمن Nuxt 3 مجموعة متنوعة من ميزات تحسين الأداء المدمجة:

TYPESCRIPT
// تحسين الصور باستخدام @nuxt/image
<NuxtImg src="/products/123.webp" width="400" height="400" loading="lazy" />

(3) الأداء: درجة Lighthouse 92، LCP 1.3 ثانية

بعد التحسين، انخفض حجم حزمة JS إلى 180 كيلوبايت (gzip)، والصور تُقدَّم تلقائياً بصيغة WebP ومتجاوبة، وLCP للشاشة الأولى 1.3 ثانية، ودرجة Lighthouse 92.


3. تقسيم الكود واهتزاز الشجرة

(1) شجرة قرار تحسين الأداء

100%
flowchart TB
    A[مشكلة أداء] --> B{ما النوع؟}
    B -->|رسم أول بطيء| C[تقسيم الكود]
    B -->|صور كبيرة| D[تحسين الصور]
    B -->|تحميلات لاحقة بطيئة| E[استراتيجية التخزين المؤقت]
    B -->|JS كبيرة جداً| F[اهتزاز الشجرة]

    C --> C1[مكوّنات كسولة]
    C --> C2[استيرادات ديناميكية]
    D --> D1[وحدة @nuxt/image]
    D --> D2[تحويل WebP]
    E --> E1[عناوين تخزين HTTP المؤقت]
    E --> E2[تخزين Nitro KV المؤقت]
    F --> F1[فحص الحزمة بـ rollup-plugin-visualizer]

(2) تحليل الحزمة

BASH
npm install -D rollup-plugin-visualizer
TYPESCRIPT
// nuxt.config.ts
import { visualizer } from 'rollup-plugin-visualizer'

export default defineNuxtConfig({
  vite: {
    plugins: [
      visualizer({ filename: 'bundle-stats.html', open: true })
    ],
    build: {
      rollupOptions: {
        output: {
          manualChunks: {
            'vendor': ['vue', 'vue-router'],
            'pinia': ['pinia']
          }
        }
      }
    }
  }
})

(1) ▶ مثال: تقسيم كود المكوّن الكسول

VUE
<template>
  <div>
    <!-- الأساسي: يُحمّل فوراً -->
    <AppHeader />
    <ProductHero :product="featured" />

    <!-- تحت الطي: تحميل كسول -->
    <LazyProductGrid :products="all" />
    <LazyProductReviews :product-id="id" />

    <!-- شرطي: يُحمّل فقط عند ظهوره -->
    <LazyNewsletterSignup v-if="showNewsletter" />
  </div>
</template>

الناتج:

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

(3) مقارنة قبل وبعد التحسين

المقياس قبل التحسين بعد التحسين التحسين
حزمة JS (gzip) 2.8 ميغابايت 180 كيلوبايت -94٪
عدد المكوّنات على الشاشة الأولى 50 8 -84٪
تحميل JS على الشاشة الأولى 2.8 ميغابايت 85 كيلوبايت -97٪
LCP 4.5 ثانية 1.3 ثانية -71٪

4. تحسين الصور

(1) ▶ مثال: تثبيت @nuxt/image

BASH
npm install @nuxt/image

الناتج:

TEXT
# تم تنفيذ الأمر بنجاح
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  image: {
    quality: 80,
    format: ['webp', 'avif'],
    screens: {
      xs: 320, sm: 640, md: 768, lg: 1024, xl: 1280, xxl: 1536
    }
  }
})

(2) ▶ مثال: صور NuxtImg المتجاوبة

VUE
<template>
  <div>
    <!-- WebP/AVIF تلقائي + srcset متجاوب -->
    <NuxtImg
      src="/images/product-123.jpg"
      width="800"
      height="600"
      format="webp"
      loading="lazy"
      sizes="sm:100vw md:50vw lg:33vw"
      :modifiers="{ quality: 80 }"
      alt="Premium Headphones"
    />

    <!-- عنصر نائب مع ضبابية -->
    <NuxtImg
      src="/images/hero.jpg"
      placeholder
      width="1920"
      height="1080"
      format="webp"
      alt="MegaShop Hero"
    />
  </div>
</template>

الناتج:

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

(3) ▶ مثال: NuxtPicture متعدد التنسيقات

VUE
<template>
  <!-- NuxtPicture: اختيار تلقائي لأفضل تنسيق حسب المتصفح -->
  <NuxtPicture
    src="/images/banner.jpg"
    width="1200"
    height="400"
    format="avif,webp"
    loading="lazy"
    alt="Sale Banner"
  />
</template>

الناتج:

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

(1) مقارنة تنسيقات الصور

التنسيق نسبة الضغط دعم المتصفح حالات الاستخدام
AVIF 🟢 الأفضل (50٪ مقابل JPG) Chrome/Edge/Firefox المتصفحات الحديثة
WebP 🟢 عالية (30٪ مقابل JPG) جميع المتصفحات الرئيسية التنسيق المُوصى به للأغراض العامة
JPEG 🟡 المرجع الجميع التوافق كبديل
PNG 🔴 كبيرة الجميع الصور الشفافة

5. استراتيجية التخزين المؤقت

(1) ▶ مثال: عناوين تخزين HTTP المؤقت

TYPESCRIPT
// nuxt.config.ts - عناوين التخزين المؤقت حسب المسار
export default defineNuxtConfig({
  routeRules: {
    // أصول ثابتة: تخزين مؤقت لسنة واحدة غير قابل للتغيير
    '/_nuxt/**': {
      headers: { 'cache-control': 'public, max-age=31536000, immutable' }
    },
    // الصور: تخزين مؤقت ليوم واحد
    '/images/**': {
      headers: { 'cache-control': 'public, max-age=86400, stale-while-revalidate=604800' }
    },
    // صفحات المنتجات: تخزين ISR مؤقت
    '/products/**': {
      swr: 86400,
      headers: { 'cache-control': 'public, s-maxage=86400, stale-while-revalidate=3600' }
    }
  }
})

الناتج:

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

(2) ▶ مثال: API تخزين Nitro KV المؤقت

TYPESCRIPT
// server/api/products/[id].get.ts - معالج مخزّن مؤقتاً
export default cachedEventHandler(
  async (event) => {
    const id = getRouterParam(event, 'id')
    const product = await fetchProductFromDB(Number(id))
    return product
  },
  {
    maxAge: 60 * 60,        // تخزين مؤقت لساعة واحدة
    swr: true,               // تقديم البيانات القديمة أثناء إعادة التحقق
    getKey: (event) => `product:${getRouterParam(event, 'id')}`,
    varies: ['Accept-Language'] // تخزين مؤقت مختلف لكل لغة
  }
)

الناتج:

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

(1) مقارنة مستويات التخزين المؤقت

المستوى الموقع السرعة طريقة التحكم
تخزين المتصفح المؤقت جهاز المستخدم ⚡⚡⚡ الأسرع عنوان Cache-Control
تخزين حافة CDN المؤقت أقرب عقدة ⚡⚡ سريع تكوين CDN + Vary
تخزين Nitro KV المؤقت ذاكرة الخادم ⚡ سريع cachedEventHandler
تخزين صفحات ISR المؤقت تخزين Nitro ⚡ سريع routeRules swr

6. مثال شامل: تكوين تحسين أداء MegaShop

TYPESCRIPT
// nuxt.config.ts - تحسين أداء كامل
export default defineNuxtConfig({
  ssr: true,

  modules: ['@nuxt/image', '@nuxtjs/tailwindcss'],

  // تحسين الصور
  image: {
    quality: 80,
    format: ['webp', 'avif'],
    screens: { xs: 320, sm: 640, md: 768, lg: 1024, xl: 1280 }
  },

  // تحسين بناء Vite
  vite: {
    build: {
      cssCodeSplit: true,
      rollupOptions: {
        output: {
          manualChunks(id) {
            if (id.includes('node_modules')) {
              if (id.includes('pinia')) return 'vendor-pinia'
              if (id.includes('vue')) return 'vendor-vue'
              return 'vendor-libs'
            }
          }
        }
      }
    }
  },

  // استراتيجية التخزين المؤقت على مستوى المسار
  routeRules: {
    '/': { prerender: true },
    '/products': { swr: 3600 },
    '/products/**': { swr: 86400 },
    '/admin/**': { ssr: false },
    '/_nuxt/**': { headers: { 'cache-control': 'public, max-age=31536000, immutable' } },
    '/images/**': { headers: { 'cache-control': 'public, max-age=86400' } }
  },

  // تلميحات أداء التطبيق
  experimental: {
    payloadExtraction: true // تقليل حجم الحمولة
  }
})
VUE
<!-- pages/index.vue - الصفحة الرئيسية المحسّنة -->
<template>
  <div>
    <AppHeader />

    <!-- فوق الطي: تحميل فوري -->
    <section class="hero">
      <NuxtImg src="/images/hero.jpg" width="1200" height="400" format="webp"
        priority alt="MegaShop" />
      <h1>MegaShop</h1>
    </section>

    <!-- تحت الطي: تحميل كسول -->
    <LazyProductGrid :products="featured" />

    <!-- شرطي: تحميل فقط عند الدخول في منطقة العرض -->
    <LazyNewsletterSignup v-if="showNewsletter" />
  </div>
</template>

<script setup lang="ts">
const { data: featured } = await useFetch('/api/products/featured')
const showNewsletter = ref(false)
</script>

❓ أسئلة شائعة

س ماذا أفعل إذا كانت درجة Lighthouse منخفضة؟
ج عالج المشاكل حسب الأولوية: 1) تحسين الصور (WebP/ضغط/تحميل كسول) → 2) تحليل حزمة JS (مكوّنات كسولة/اهتزاز الشجرة) → 3) استراتيجية التخزين المؤقت (عناوين HTTP/ISR) → 4) تحسين الخطوط.
س هل يدعم @nuxt/image عناوين URL للصور الخارجية؟
ج نعم، كوّن image.domains لإضافة نطاقات خارجية: image: { domains: ['cdn.example.com'] }. NuxtImg سيحسّن الصور الخارجية تلقائياً.
س ما الفرق بين NuxtImg ووسم img العادي؟
ج NuxtImg يُنشئ تلقائياً srcset، ويحوّل الصور إلى WebP/AVIF، ويقصها لتناسب أبعاد الجهاز، ويفعّل التحميل الكسول. مع وسم img العادي، تحتاج لمعالجة كل هذه التحسينات يدوياً.
س أيهما يأخذ الأسبقية: تخزين ISR المؤقت أم تخزين HTTP المؤقت؟
ج ISR هو تخزين مؤقت من جانب الخادم (مخزّن في Nitro)، بينما تخزين HTTP المؤقت يحدث على مستوى المتصفح/CDN. تدفق الطلب: تخزين المتصفح → تخزين CDN → Nitro ISR → عرض ديناميكي. كل طبقة تعمل بشكل مستقل.
س ما الفخاخ التي يجب الانتباه لها عند تكوين manualChunks؟
ج لا تضمّن كود جانب الخادم في مكوّنات العميل. Nuxt 3 يتولى تلقائياً فصل كود الخادم والعميل. يجب استخدام manualChunks فقط لتقسيم المكتبات الخارجية.
س هل من الصعب الوصول إلى درجة Lighthouse 90+؟
ج يمكنك الوصول إلى 90+ مع SSR وتحسين الصور واستراتيجية التخزين المؤقت. الجزء الأصعب هو إبقاء LCP أقل من 2.5 ثانية—يجب تبسيط مسار العرض الحرج وتحميل الموارد الأساسية فقط على الشاشة الأولى.

📖 ملخص


📝 تمارين

  1. تمرين أساسي (الصعوبة: ⭐): ثبّت @nuxt/image، واستبدل جميع وسوم img بـ NuxtImg، وتحقق من تحويل WebP التلقائي.
  2. تمرين متقدم (الصعوبة: ⭐⭐): استخدم rollup-plugin-visualizer لتحليل الحزمة، وحدد أكبر تبعية، وكوّن manualChunks لتقسيمها.
  3. تحدٍ (الصعوبة: ⭐⭐⭐): حقّق درجة Lighthouse 90+: تحسين الصور + تقسيم الكود + استراتيجيات التخزين المؤقت، باستخدام Lighthouse CI للتدقيق الآلي

---|

Web-Tutorial.com

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

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

100%