ما قبل مرحلة الإنتاج في Next.js
إليك بعض النصائح الهامة لتضمن أفضل تجربة مستخدم عندما تصل بتطبيق Next.js إلى مرحلة الإنتاج.
نصائح عامة
- استخدم التخزين المؤقت caching أينما أتيح لك ذلك.
- تأكد من أن قواعد البيانات والواجهة الخلفية لتطبيقك من نفس الأصل (انشرهما ضمن نفس الموقع).
- حاول أن تشحن أقل كمية ممكنة من شيفرة JavaScript.
- أخِّر تحميل تجميعات JavaScript الصعبة حتى تحتاجها.
- تأكد من إعداد آلية للعمل مع السجلات logging.
- تأكد من إعداد آلية لمعالجة الأخطاء.
- هيئ صفحات للحالة 404 (غير موجود) وللحالة 500 (خطأ).
- تأكد من قياسك لأداء التطبيق.
- استخدم الأداة Lighthouse للتحقق من الأداء وتطبيقك لأفضل الممارسات وشمولية الوصول وتطبيقك لمعايير تحسين محركات البحث SEO. للحصول على أفضل النتائج، استخدم نسخة الإنتاج في متصفحك في نمط التخفي incognito كي لا تتأثر النتائج بالتوسعات extensions المثبتة على المتصفح.
- راجع صفحة المتصفحات والميزات المدعومة من توثيق Next.js
- حسِّن الأداء من خلال استخدام:
- حسن أداء التطبيق من ناحية التحميل.
التخزين المؤقت في Next.js
يُحسّن التخزين المؤقت للبيانات زمن الاستجاية و يقلل عدد الطلبات المرسلة إلى خدمة خارجية. تضيف Next.js تلقائيًا ترويسة التخزين المؤقت إلى الموجودات التي لا تتغير في المجلد next/static_/
مثل ملفات JavaScript و CSS والصور الساكنة وغيرها من الوسائط.
Cache-Control: public, max-age=31536000, immutable
ستُلغى قية الترويسة Cache-Control
الموجودة في الملف next.config.js
في مرحلة الإنتاج للتأكد من إمكانية التخزين المؤقت للموجودات الساكنة بفعالية. فإن أرد التحقق من بيانات التخزين المؤقت لصفحة وّلدت بشكل ساكن، اضبط قيمة الخاصية revalidate
في الدالة getStaticProps
الخاصة بهذه الصفحة. وإن كنت تستخدم المكوّن next/image
فهنالك بعض القواعد الخاصة بالتخزين المؤقت لمحمَّل الصور المحسَّنة.
ملاحظة: عندما تشغّل تطبيقك محليًا بتنفيذ الأمر 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
افتراضيًا بشكل مختلف وفقًا لطريقة إحضار البيانات في الصفحة.
- تأخذ الترويسة القيمة
next start
إن استخدمت الصفحة إحدى الدالتينgetServerSideProps
أوgetInitialProps
لكي تمنع التخزين المؤقت العَرضي للاستجابة التي لا يمكن تخزينها مؤقتًا. إن أردت استخدام أسلوب آخر للتخزين المؤقت مع الدالة يمكنك استخدام التابع التالي داخل هذه الدالة:
res.setHeader('Cache-Control', 'value_you_prefer')
- إن استخدمت الصفحة الدالة
getStaticProps
ستمتلك الترويسةCache-Control
الصيغة التالية لتخزين البيانات مؤقتًا أطول فترة ممكنة:
s-maxage=REVALIDATE_SECONDS, stale-while-revalidate
s-maxage=31536000, stale-while-revalidate //revalidate
ملاحظة: لا بد أن يدعم مزّوّد الاستضافة التخزين المؤقت للاستجابة الديناميكة. فإن كنت تستضيف تطبيقك بنفسك، فعليك أن تضيف المنطق السابق بنفسك من خلال التخزين بتقنية مفتاح/قيمة مثل Redis. كما سيساعدك Edge Caching دون أية إعدادات إن كنت تستخدم Vercel.
تخفيض حجم JavaScript
لتقليل حجم JavaScript المرسلة إلى المتصفح، تستطيع استخدام الأدوات التالية لفهم محتويات كل تجميع من تجميعات JavaScript:
- Import Cost: تعرض حجم الحزمة المدرجة ضمن الشيفرة في بيئة VSCode (فيجوال ستدوديو كود).
- Package Phobia: يحسب تبعات إضافة اعتمادية تطوير جديدة إلى مشروعك.
- Bundle Phobia: يحلل مقدار الزيادة التي تسببها اعتمادية في حجم التجميعات.
- Webpack Bundle Analyzer: يعرض حجم ملف الخرج لحزمة webpack بأسلوب بصري تفاعلي على شكل خريطة شجرية قابلة للتكبير.
تُفصل شيفرة JavaScript لكل ملف موجود في المجلد /pages
تلقائيًا ضمن تجميعة خاصة عند بناء التطبيق next build
. بإمكانك أيضًا استخدام الإدراج الديناميكي لإبطاء تحميل المكوّنات و المكتبات، إذ قد ترغب مثلًا في تأخير تحميل شيفرة وحدة برمجية حتى ينقر المستخدم على زر مثلًا.
إدارة السجلات في Next.js
تعمل Next.js على جانبي الخادم والعميل وبالتالي ستجد عدة نماذج لدعم إدارة السجلات والرسائل:
console.log
من جانب المتصفح.stdout
من جانب الخادم.
لكن إن أردت استخدام حزمة مُهيكلة لإدارة السجلات سننصحك بالحزمة Pino، وإن كنت تعمل على Vercel، فهناك حزمة متكاملة مدمجة لإدارة السجلات تتوافق مع Next.js.
التعامل مع الأخطاء
بإمكانك عند وقوع خطأ غير متوقع أثناء تنفيذ الشيفرة التحكم بطريقة عرضه للمستخدم باستخدام الصفحة "500". ويُفضّل أن تخصص هذه الصفحة بما يلائم تطبيقك بدلًا من صفحة Next.js الافتراضية. كما يمكنك تتبع وتسجيل الاستثناءات والأخطاء من خلال أدوات مثل Sentry.
أداء التطبيق أثناء التحميل
لابد أولًا كي تحسن أداء التطبيق أثناء التحميل من تحديد ما ينبغي قياسه وكيفية قياسه، وتُعد مؤشرات ويب الحيوية Core Web Vitals معيارًا جيدًا يمكن قياسه من خلال المتصفح. إن لم تكن على دراية بحيثيات هذه المؤشرات، بإمكانك البحث عنها عبر الإنترنت واختيار المؤشرات المحددة التي تناسبك في تحديد أداء التحميل لتطبيق. وقد ترغب (كعمل نموذجي) في قياس اداء التحميل في البيئات التالية:
- في المختبر من خلال حاسوبك الشخصي أو المحاكي.
- في حقل العمل باستخدام بيانات حقيقية لزوار فعليين.
- محليًا من خلال اختبار تنفّذه على جهازك.
- عن بعد من خلال اختبار تجريه على حساب سحابي.
كرر استعمل الاستراتيجيات التالية بمجرد أن تنتهي من اختبار أداء التحميل، طبق استراتيجية ثم قس الأداء وحاول أن تحسِّن في التطبيق قدر المستطتع ثم انتقل إلى الأخرى:
- استخدم التخزين المؤقت في الأماكن القريبة من مكان نشر قاعدة البيانات أو الواجهة البرمجية API.
- استخدم القيمة التي لن تزيد الحمولة على الواجهة الخلفية للتطبيق.
- استخدم التجديد التدريجي الساكن للتقليل من عدد الطلبات التي ترسلها إلى الواجهة الخلفية.
- أزل شيفرة JavaScript غير المستخدمة.
يمكن أن تعطيك بعض مؤشرات ويب الحيوية فكرة عن مدى تأثير حجم التجميعات والاستراتيجيات التي تخفف من هذه التأثيرات مثل:
- ضبط إعدادات محرر الشيفرة لديك ليعرض تبعات إدراج الاعتماديات وأحجامها.
- الحصول على حزم بديلة أصغر.
- التحميل الديناميكي للمكوّنات و الاعتماديات.
المصادر
- الصفحة Going to Production من توثيق Next.js الرسمي.