كيفية استضافة تطبيق Next.js بنفسك

عند نشر تطبيق Next.js الخاص بك، قد ترغب في تكيف كيفية معالجة الميزات المختلفة بناءً على بنيتك التحتية.

🎥 شاهد: تعرف على المزيد حول استضافة Next.js بنفسك → YouTube (45 دقيقة).

تحسين الصور

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

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

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

Middleware

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

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

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

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

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

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

يمكنك قراءة متغيرات البيئة بأمان على الخادم أثناء التصيير الديناميكي.

import { connection } from 'next/server'

export default async function Component() {
  await connection()
  // ملفات تعريف الارتباط، الرؤوس، وواجهات برمجة التطبيقات الديناميكية الأخرى
  // ستختار أيضًا التصيير الديناميكي، مما يعني
  // أن متغير البيئة هذا يتم تقييمه في وقت التشغيل
  const value = process.env.MY_VALUE
  // ...
}
import { connection } from 'next/server'

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

هذا يسمح لك باستخدام صورة Docker واحدة يمكن ترقيتها عبر بيئات متعددة بقيم مختلفة.

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

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

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

يستخدم التخزين المؤقت وإعادة التحقق من الصفحات (مع التجديد الثابت التدريجي) نفس التخزين المؤقت المشترك. بشكل افتراضي، يتم تخزين هذا التخزين المؤقت في نظام الملفات (على القرص) على خادم 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(tags) {
    // tags إما سلسلة أو مصفوفة من السلاسل
    tags = [tags].flat()
    // التكرار عبر جميع الإدخالات في التخزين المؤقت
    for (let [key, value] of cache) {
      // إذا كانت علامات القيمة تتضمن العلامة المحددة، احذف هذا الإدخال
      if (value.tags.some((tag) => tags.includes(tag))) {
        cache.delete(key)
      }
    }
  }

  // إذا كنت تريد أن يكون لديك تخزين مؤقت مؤقت في الذاكرة لطلب واحد يتم إعادة تعيينه
  // قبل الطلب التالي، يمكنك الاستفادة من هذه الطريقة
  resetRequestCache() {}
}

سيسمح لك استخدام معالج تخزين مؤقت مخصص بضمان الاتساق عبر جميع النسخ التي تستضيف تطبيق 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 في مثل هذه التنقلات.

البث و Suspense

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

على سبيل المثال، يمكنك تعطيل التخزين المؤقت في Nginx عن طريق تعيين X-Accel-Buffering إلى no:

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*{/}?',
        headers: [
          {
            key: 'X-Accel-Buffering',
            value: 'no',
          },
        ],
      },
    ]
  },
}

التصيير المسبق الجزئي

التصيير المسبق الجزئي (تجريبي) يعمل بشكل افتراضي مع Next.js وليس ميزة CDN فقط. يشمل ذلك النشر كخادم Node.js (عبر next start) وعند استخدامه مع حاوية Docker.

الاستخدام مع CDNs

عند استخدام CDN أمام تطبيق Next.js الخاص بك، ستتضمن الصفحة رأس استجابة Cache-Control: private عند الوصول إلى واجهات برمجة التطبيقات الديناميكية. هذا يضمن تمييز صفحة HTML الناتجة على أنها غير قابلة للتخزين المؤقت. إذا كانت الصفحة ممثلة مسبقًا بالكامل إلى ثابت، فستتضمن Cache-Control: public للسماح بتخزين الصفحة مؤقتًا على CDN.

إذا كنت لا تحتاج إلى مزيج من المكونات الثابتة والديناميكية، يمكنك جعل مسارك بالكامل ثابتًا وتخزين HTML الناتج مؤقتًا على CDN. هذا التحسين الثابت التلقائي هو السلوك الافتراضي عند تشغيل next build إذا لم يتم استخدام واجهات برمجة التطبيقات الديناميكية.

مع انتقال التصيير المسبق الجزئي إلى الاستقرار، سنوفر الدعم عبر واجهة برمجة تطبيقات محولات النشر.

after

after مدعوم بالكامل عند الاستضافة الذاتية مع next start.

عند إيقاف الخادم، تأكد من إيقاف التشغيل السلس عن طريق إرسال إشارات SIGINT أو SIGTERM والانتظار. هذا يسمح لخادم Next.js بالانتظار حتى تنتهي وظائف رد الاتصال المعلقة أو الوعود المستخدمة داخل after.