الانتقال إلى مرحلة الإنتاج

قبل نشر تطبيق Next.js الخاص بك في مرحلة الإنتاج، إليك بعض التوصيات لضمان أفضل تجربة للمستخدم.

بشكل عام

التخزين المؤقت (Caching)

أمثلة

يحسن التخزين المؤقت أوقات الاستجابة ويقلل عدد الطلبات إلى الخدمات الخارجية. يقوم Next.js تلقائيًا بإضافة رؤوس تخزين مؤقت للأصول الثابتة التي يتم تقديمها من /_next/static بما في ذلك JavaScript، CSS، الصور الثابتة، ووسائط أخرى.

Cache-Control: public, max-age=31536000, immutable

سيتم استبدال رؤوس Cache-Control المحددة في next.config.js في بيئة الإنتاج لضمان إمكانية تخزين الأصول الثابتة بشكل فعال. إذا كنت بحاجة إلى إعادة التحقق من صحة التخزين المؤقت لصفحة تم إنشاؤها بشكل ثابت، يمكنك فعل ذلك عن طريق تعيين revalidate في دالة getStaticProps الخاصة بالصفحة. إذا كنت تستخدم next/image، يمكنك ضبط minimumCacheTTL لمحمل تحسين الصور الافتراضي.

معلومة مفيدة: عند تشغيل التطبيق محليًا باستخدام next dev، يتم استبدال الرؤوس لمنع التخزين المؤقت محليًا.

Cache-Control: no-cache, no-store, max-age=0, must-revalidate

يمكنك أيضًا استخدام رؤوس التخزين المؤقت داخل getServerSideProps ومسارات API للاستجابات الديناميكية. على سبيل المثال، باستخدام stale-while-revalidate.

// تعتبر هذه القيمة طازجة لمدة عشر ثوانٍ (s-maxage=10).
// إذا تم تكرار الطلب خلال الثواني العشر التالية، ستظل القيمة المخزنة مؤقتًا طازجة. إذا تم تكرار الطلب قبل 59 ثانية،
// ستكون القيمة المخزنة مؤقتًا قديمة ولكنها ستظل تُعرض (stale-while-revalidate=59).
//
// في الخلفية، سيتم إرسال طلب إعادة تحقق لتعبئة التخزين المؤقت
// بقيمة طازجة. إذا قمت بتحديث الصفحة، سترى القيمة الجديدة.
export async function getServerSideProps({ req, res }) {
  res.setHeader(
    'Cache-Control',
    'public, s-maxage=10, stale-while-revalidate=59'
  )

  return {
    props: {},
  }
}

بشكل افتراضي، سيتم تعيين رؤوس Cache-Control بشكل مختلف اعتمادًا على كيفية جلب البيانات في صفحتك.

  • إذا كانت الصفحة تستخدم getServerSideProps أو getInitialProps، فستستخدم رأس Cache-Control الافتراضي المعين بواسطة next start لمنع التخزين المؤقت العرضي للاستجابات التي لا يمكن تخزينها مؤقتًا. إذا كنت تريد سلوك تخزين مؤقت مختلف أثناء استخدام getServerSideProps، استخدم res.setHeader('Cache-Control', 'value_you_prefer') داخل الدالة كما هو موضح أعلاه.
  • إذا كانت الصفحة تستخدم getStaticProps، فسيكون لها رأس Cache-Control بقيمة s-maxage=REVALIDATE_SECONDS, stale-while-revalidate، أو إذا لم يتم استخدام revalidate، s-maxage=31536000, stale-while-revalidate للتخزين المؤقت لأقصى مدة ممكنة.

معلومة مفيدة: يجب أن يدعم موفر النشر الخاص بك التخزين المؤقت للاستجابات الديناميكية. إذا كنت تستضيف التطبيق بنفسك، فستحتاج إلى إضافة هذا المنطق بنفسك باستخدام مخزن مفتاح/قيمة مثل Redis. إذا كنت تستخدم Vercel، يعمل تخزين الحافة (Edge Caching) دون الحاجة إلى تكوين.

تقليل حجم JavaScript

أمثلة

لتقليل كمية JavaScript المرسلة إلى المتصفح، يمكنك استخدام الأدوات التالية لفهم ما يتم تضمينه داخل كل حزمة JavaScript:

  • Import Cost – عرض حجم الحزمة المستوردة داخل VSCode.
  • Package Phobia – اكتشف تكلفة إضافة تبعية تطوير جديدة إلى مشروعك.
  • Bundle Phobia - حلل كيف يمكن لتبعية ما أن تزيد أحجام الحزم.
  • Webpack Bundle Analyzer – تصور حجم ملفات إخراج webpack مع خريطة شجرية تفاعلية قابلة للتكبير.
  • bundlejs - أداة عبر الإنترنت لحزم وضغط مشاريعك بسرعة، مع عرض حجم الحزمة المضغوطة gzip/brotli، كل ذلك يعمل محليًا في متصفحك.

سيتم تقسيم كل ملف داخل دليل pages/ تلقائيًا إلى حزمة JavaScript الخاصة به أثناء next build. يمكنك أيضًا استخدام الاستيراد الديناميكي لتحميل المكونات والمكتبات عند الحاجة. على سبيل المثال، قد ترغب في تأخير تحميل كود النافذة المنبثقة حتى ينقر المستخدم على زر الفتح.

تسجيل الأحداث (Logging)

أمثلة

بما أن Next.js يعمل على كل من العميل والخادم، فهناك أشكال متعددة من تسجيل الأحداث المدعومة:

  • console.log في المتصفح
  • stdout على الخادم

إذا كنت تريد حزمة تسجيل منظمة، نوصي بـ Pino. إذا كنت تستخدم Vercel، فهناك تكاملات تسجيل جاهزة متوافقة مع Next.js.

معالجة الأخطاء (Error Handling)

أمثلة

عند حدوث استثناء غير معالج، يمكنك التحكم في تجربة المستخدمين باستخدام صفحة 500. نوصي بتخصيص هذه الصفحة لتناسب علامتك التجارية بدلاً من سمة Next.js الافتراضية.

يمكنك أيضًا تسجيل وتتبع الاستثناءات باستخدام أداة مثل Sentry. يُظهر هذا المثال كيفية التقاط وإبلاغ الأخطاء على كل من جانب العميل والخادم، باستخدام SDK Sentry لـ Next.js. هناك أيضًا تكامل Sentry لـ Vercel.

أداء التحميل (Loading Performance)

لتحسين أداء التحميل، تحتاج أولاً إلى تحديد ما يجب قياسه وكيفية قياسه. مؤشرات الويب الأساسية (Core Web Vitals) هي معيار صناعي جيد يتم قياسه باستخدام متصفح الويب الخاص بك. إذا لم تكن على دراية بمقاييس Core Web Vitals، راجع هذه المقالة وحدد المقاييس المحددة التي ستكون محركًا لأداء التحميل لديك. من الناحية المثالية، سترغب في قياس أداء التحميل في البيئات التالية:

  • في المختبر، باستخدام جهازك الخاص أو محاكي.
  • في الميدان، باستخدام بيانات من العالم الحقيقي من الزوار الفعليين.
  • محليًا، باستخدام اختبار يعمل على جهازك.
  • عن بُعد، باستخدام اختبار يعمل في السحابة.

بمجرد أن تتمكن من قياس أداء التحميل، استخدم الاستراتيجيات التالية لتحسينه تدريجيًا بحيث تطبق استراتيجية واحدة، تقيس الأداء الجديد وتستمر في الضبط حتى لا ترى تحسنًا كبيرًا. ثم يمكنك الانتقال إلى الاستراتيجية التالية.

  • استخدم مناطق التخزين المؤقت القريبة من المناطق التي يتم فيها نشر قاعدة البيانات أو API.
  • كما هو موضح في قسم التخزين المؤقت، استخدم قيمة stale-while-revalidate التي لن تثقل كاهل خلفيتك.
  • استخدم التجديد الثابت التدريجي (Incremental Static Regeneration) لتقليل عدد الطلبات إلى خلفيتك.
  • احذف JavaScript غير المستخدم. راجع هذه المقالة لفهم مقاييس Core Web Vitals التي يؤثر عليها حجم الحزمة وما هي الاستراتيجيات التي يمكنك استخدامها لتقليلها، مثل:
    • إعداد محرر الأكواد لعرض تكاليف وأحجام الاستيراد
    • البحث عن حزم بديلة أصغر حجمًا
    • تحميل المكونات والتبعيات بشكل ديناميكي