النشر

تهانينا، حان وقت النشر إلى بيئة الإنتاج.

يمكنك نشر Next.js المُدار مع Vercel، أو استضافة ذاتية على خادم Node.js، صورة Docker، أو حتى ملفات HTML ثابتة. عند النشر باستخدام next start، جميع ميزات Next.js مدعومة.

بناءات الإنتاج

تشغيل next build يولد نسخة مُحسنة من تطبيقك للإنتاج. يتم إنشاء ملفات HTML وCSS وJavaScript بناءً على صفحاتك. يتم تجميع JavaScript وتصغير حزم المتصفح باستخدام مُجمّع Next.js لتحقيق أفضل أداء ودعم جميع المتصفحات الحديثة.

ينتج Next.js ناتج نشر قياسي يُستخدم في النشر المُدار والذاتي لـ Next.js. هذا يضمن دعم جميع الميزات في كلا طريقي النشر. في الإصدار الرئيسي القادم، سنحول هذا الناتج إلى مواصفات Build Output API.

Next.js المُدار مع Vercel

Vercel، مبتكرو Next.js والمشرفون عليها، يوفرون بنية تحتية مُدارة ومنصة تجربة مطور لتطبيقات Next.js الخاصة بك.

النشر على Vercel لا يتطلب أي إعدادات ويوفر تحسينات إضافية للتوسع، التوفر، والأداء عالميًا. ومع ذلك، جميع ميزات Next.js لا تزال مدعومة عند الاستضافة الذاتية.

تعلم المزيد عن Next.js على Vercel أو انشر قالبًا مجانًا لتجربته.

الاستضافة الذاتية

يمكنك استضافة Next.js ذاتيًا بثلاث طرق مختلفة:

خادم Node.js

يمكن نشر Next.js على أي مزود استضافة يدعم Node.js. تأكد من أن ملف package.json يحتوي على نصوص "build" و"start":

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

ثم، قم بتشغيل npm run build لبناء تطبيقك. أخيرًا، قم بتشغيل npm run start لبدء خادم Node.js. يدعم هذا الخادم جميع ميزات Next.js.

صورة Docker

يمكن نشر Next.js على أي مزود استضافة يدعم حاويات Docker. يمكنك استخدام هذه الطريقة عند النشر على منصات تنسيق الحاويات مثل Kubernetes أو عند التشغيل داخل حاوية في أي مزود سحابي.

  1. ثبّت Docker على جهازك
  2. انسخ مثالنا (أو مثال البيئات المتعددة)
  3. ابنِ حاويتك: docker build -t nextjs-docker .
  4. شغّل حاويتك: docker run -p 3000:3000 nextjs-docker

يدعم Next.js عبر Docker جميع ميزات Next.js.

تصدير HTML ثابت

يتيح Next.js البدء كموقع ثابت أو تطبيق صفحة واحدة (SPA)، ثم الترقية لاحقًا لاستخدام الميزات التي تتطلب خادمًا.

بما أن Next.js يدعم هذا التصدير الثابت، يمكن نشره واستضافته على أي خادم ويب يمكنه تقديم أصول ثابتة HTML/CSS/JS. يتضمن ذلك أدوات مثل AWS S3 أو Nginx أو Apache.

التشغيل كـ تصدير ثابت لا يدعم ميزات Next.js التي تتطلب خادمًا. تعلم المزيد.

معلومة مفيدة:

الميزات

تحسين الصور

تحسين الصور عبر next/image يعمل مع الاستضافة الذاتية دون أي إعدادات عند النشر باستخدام next start. إذا كنت تفضل أن يكون لديك خدمة منفصلة لتحسين الصور، يمكنك تكوين محمل صور.

يمكن استخدام تحسين الصور مع تصدير ثابت عن طريق تعريف محمل صور مخصص في next.config.js. لاحظ أن الصور يتم تحسينها أثناء التشغيل، وليس أثناء البناء.

معلومة مفيدة:

  • عند الاستضافة الذاتية، فكر في تثبيت sharp لتحسين أداء تحسين الصور في بيئة الإنتاج عن طريق تشغيل npm install sharp في دليل مشروعك. على منصات Linux، قد يحتاج sharp إلى إعدادات إضافية لمنع استخدام الذاكرة المفرط.
  • تعلم المزيد عن سلوك التخزين المؤقت للصور المحسنة وكيفية تكوين TTL.
  • يمكنك أيضًا تعطيل تحسين الصور والاستفادة من المزايا الأخرى لاستخدام next/image إذا كنت تفضل ذلك. على سبيل المثال، إذا كنت تقوم بتحسين الصور بنفسك بشكل منفصل.

Middleware

Middleware يعمل مع الاستضافة الذاتية دون أي إعدادات عند النشر باستخدام next start. نظرًا لأنه يتطلب الوصول إلى الطلب الوارد، فهو غير مدعوم عند استخدام تصدير ثابت.

يستخدم Middleware وقت تشغيل وهو مجموعة فرعية من جميع واجهات برمجة تطبيقات Node.js المتاحة للمساعدة في ضمان زمن انتقال منخفض، حيث قد يعمل أمام كل مسار أو أصل في تطبيقك. لا يتطلب هذا وقت التشغيل تشغيل "على الحافة" ويعمل في خادم أحادي المنطقة. هناك حاجة إلى إعدادات إضافية وبنية تحتية لتشغيل Middleware في مناطق متعددة.

إذا كنت تبحث عن إضافة منطق (أو استخدام حزمة خارجية) تتطلب جميع واجهات برمجة تطبيقات Node.js، فقد تتمكن من نقل هذا المنطق إلى تخطيط كمكون خادم. على سبيل المثال، التحقق من الرؤوس وإعادة التوجيه. يمكنك أيضًا استخدام الرؤوس أو ملفات تعريف الارتباط أو معلمات الاستعلام لـ إعادة التوجيه أو إعادة الكتابة عبر next.config.js. إذا لم ينجح ذلك، يمكنك أيضًا استخدام خادم مخصص.

متغيرات البيئة

يمكن لـ Next.js دعم متغيرات البيئة في وقت البناء ووقت التشغيل.

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

لقراءة متغيرات البيئة في وقت التشغيل، نوصي باستخدام getServerSideProps أو الترقية التدريجية لموجه التطبيق. مع موجه التطبيق، يمكننا قراءة متغيرات البيئة بأمان على الخادم أثناء التقديم الديناميكي. هذا يسمح لك باستخدام صورة Docker واحدة يمكن ترقيتها عبر بيئات متعددة بقيم مختلفة.

import { unstable_noStore as noStore } from 'next/cache';

export default function Component() {
  noStore();
  // ملفات تعريف الارتباط ()، الرؤوس ()، وغيرها من الوظائف الديناميكية
  // ستختار أيضًا التقديم الديناميكي، مما يجعل
  // متغير البيئة هذا يتم تقييمه في وقت التشغيل
  const value = process.env.MY_VALUE
  ...
}

معلومة مفيدة:

  • يمكنك تشغيل التعليمات البرمجية عند بدء تشغيل الخادم باستخدام وظيفة register.
  • لا نوصي باستخدام خيار runtimeConfig، لأنه لا يعمل مع وضع الإخراج المستقل. بدلاً من ذلك، نوصي بالترقية التدريجية لموجه التطبيق.

التخزين المؤقت و ISR

يمكن لـ Next.js تخزين الاستجابات وصفحات ثابتة مولدة ومخرجات بناء وأصول ثابتة أخرى مثل الصور والخطوط والنصوص البرمجية.

يستخدم التخزين المؤقت وإعادة التحقق من الصفحات (باستخدام التوليد الثابت التدريجي (ISR) أو وظائف أحدث في موجه التطبيق نفس التخزين المؤقت المشترك. افتراضيًا، يتم تخزين هذا التخزين المؤقت في نظام الملفات (على القرص) على خادم Next.js الخاص بك. يعمل هذا تلقائيًا عند الاستضافة الذاتية باستخدام كل من موجه الصفحات وموجه التطبيق.

يمكنك تكوين موقع التخزين المؤقت لـ Next.js إذا كنت تريد الاحتفاظ بالصفحات والبيانات المخزنة مؤقتًا في تخزين دائم، أو مشاركة التخزين المؤقت عبر عدة حاويات أو نسخ من تطبيق Next.js الخاص بك.

التخزين المؤقت التلقائي

  • يضبط Next.js رأس Cache-Control على public, max-age=31536000, immutable للأصول الثابتة حقًا. لا يمكن تجاوزه. تحتوي هذه الملفات الثابتة على تجزئة SHA في اسم الملف، لذا يمكن تخزينها مؤقتًا إلى أجل غير مسمى بأمان. على سبيل المثال، استيراد الصور الثابتة. يمكنك تكوين TTL للصور.
  • يضبط التوليد الثابت التدريجي (ISR) رأس Cache-Control على s-maxage: <revalidate in getStaticProps>, stale-while-revalidate. يتم تعريف وقت إعادة التحقق هذا في وظيفة getStaticProps بالثواني. إذا قمت بتعيين revalidate: false، فسيتم تعيين مدة التخزين المؤقت الافتراضية إلى سنة واحدة.
  • تعيين الصفحات المقدمة ديناميكيًا رأس Cache-Control على private, no-cache, no-store, max-age=0, must-revalidate لمنع تخزين البيانات الخاصة بالمستخدم مؤقتًا. ينطبق هذا على كل من موجه التطبيق وموجه الصفحات. يتضمن هذا أيضًا وضع المسودة.

الأصول الثابتة

إذا كنت تريد استضافة أصول ثابتة على نطاق أو CDN مختلف، يمكنك استخدام تكوين assetPrefix في next.config.js. سيستخدم Next.js هذه البادئة عند استرداد ملفات JavaScript أو CSS. فصل أصولك إلى نطاق مختلف له عيب الوقت الإضافي المستغرق في تحليل DNS و TLS.

تعلم المزيد عن assetPrefix.

تكوين التخزين المؤقت

افتراضيًا، سيتم تخزين الأصول المخزنة مؤقتًا في الذاكرة (50 ميجابايت افتراضيًا) وعلى القرص. إذا كنت تستضيف Next.js باستخدام منصة تنسيق حاويات مثل Kubernetes، سيكون لكل نسخة نسخة من التخزين المؤقت. لمنع عرض بيانات قديمة لأن التخزين المؤقت غير مشترك بين النسخ افتراضيًا، يمكنك تكوين التخزين المؤقت لـ Next.js لتوفير معالج تخزين مؤقت وتعطيل التخزين المؤقت في الذاكرة.

لتكوين موقع ISR/تخزين البيانات المؤقت عند الاستضافة الذاتية، يمكنك تكوين معالج مخصص في ملف next.config.js الخاص بك:

next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // تعطيل التخزين المؤقت في الذاكرة الافتراضي
}

ثم، أنشئ cache-handler.js في جذر مشروعك، على سبيل المثال:

cache-handler.js
const cache = new Map()

module.exports = class CacheHandler {
  constructor(options) {
    this.options = options
  }

  async get(key) {
    // يمكن تخزين هذا في أي مكان، مثل تخزين دائم
    return cache.get(key)
  }

  async set(key, data, ctx) {
    // يمكن تخزين هذا في أي مكان، مثل تخزين دائم
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    })
  }

  async revalidateTag(tag) {
    // التكرار على جميع المدخلات في التخزين المؤقت
    for (let [key, value] of cache) {
      // إذا كانت علامات القيمة تتضمن العلامة المحددة، احذف هذه المدخلة
      if (value.tags.includes(tag)) {
        cache.delete(key)
      }
    }
  }
}

سيسمح لك استخدام معالج تخزين مؤقت مخصص بضمان الاتساق عبر جميع النسخ التي تستضيف تطبيق Next.js الخاص بك. على سبيل المثال، يمكنك حفظ القيم المخزنة مؤقتًا في أي مكان، مثل Redis أو AWS S3.

معلومة مفيدة:

  • revalidatePath هي طبقة ملائمة فوق علامات التخزين المؤقت. استدعاء revalidatePath سيستدعي وظيفة revalidateTag مع علامة افتراضية خاصة للصفحة المقدمة.

تخزين البناء المؤقت

ينشئ Next.js معرفًا أثناء next build لتحديد إصدار التطبيق الذي يتم تقديمه. يجب استخدام نفس البناء وتشغيله في حاويات متعددة.

إذا كنت تقوم بإعادة البناء لكل مرحلة من بيئتك، فستحتاج إلى إنشاء معرف بناء متسق للاستخدام بين الحاويات. استخدم أمر generateBuildId في next.config.js:

next.config.js
module.exports = {
  generateBuildId: async () => {
    // يمكن أن يكون هذا أي شيء، باستخدام أحدث تجزئة git
    return process.env.GIT_HASH
  },
}

انحراف الإصدار

سيقوم Next.js تلقائيًا بالتخفيف من معظم حالات انحراف الإصدار وإعادة تحميل التطبيق تلقائيًا لاسترداد الأصول الجديدة عند الكشف عنها. على سبيل المثال، إذا كان هناك عدم تطابق في deploymentId، فإن الانتقالات بين الصفحات ستؤدي إلى تنقل صعب بدلاً من استخدام قيمة مسبقة الجلب.

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

يوفر Vercel حماية إضافية من الانحراف لتطبيقات Next.js لضمان أن الأصول والوظائف من الإصدار السابق لا تزال متاحة للعملاء القدامى، حتى بعد نشر الإصدار الجديد.

يمكنك تكوين خاصية deploymentId يدويًا في ملف next.config.js الخاص بك لضمان استخدام كل طلب إما سلسلة استعلام ?dpl أو رأس x-deployment-id.

الإيقاف اليدوي الآمن

عند استضافة التطبيق ذاتيًا، قد ترغب في تنفيذ كود معين عند إيقاف الخادم عند استقبال إشارات SIGTERM أو SIGINT.

يمكنك تعيين متغير البيئة NEXT_MANUAL_SIG_HANDLE إلى true ثم تسجيل معالج للإشارة داخل ملف _document.js. يجب تسجيل متغير البيئة مباشرة في سكريبت package.json وليس في ملف .env.

معلومة مفيدة: معالجة الإشارات اليدوية غير متاحة في وضع next dev.

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "NEXT_MANUAL_SIG_HANDLE=true next start"
  }
}
pages/_document.js
if (process.env.NEXT_MANUAL_SIG_HANDLE) {
  process.on('SIGTERM', () => {
    console.log('Received SIGTERM: cleaning up')
    process.exit(0)
  })
  process.on('SIGINT', () => {
    console.log('Received SIGINT: cleaning up')
    process.exit(0)
  })
}