تخطَّ إلى المحتوى

الترقية إلى Next.js 16: ما يفشل بصوت عالٍ وما يتغيّر بصمت

معظم التغييرات الكاسرة في الإصدار 16 توقف البناء، وهذا ما يجعلها آمنة. ما يستحق التخطيط له هو القليل منها الذي يغيّر السلوك دون أن يخبرك.

4 دقيقة قراءة

يحمل Next.js 16 قائمة طويلة من التغييرات الكاسرة، ومعظمها من النوع الجيد: يوقف البناء. تشغّلونه، فيفشل، فتُصلحونه، وتمضون.

ما يستحق القراءة بتمعّن هو القليل منها الذي يغيّر السلوك دون أن يفشل شيء. هذه هي التي تصل إلى الإنتاج.

كُتب هذا من قاعدة شيفرة تعمل على 16.3 - الموقع الذي تقرأونه الآن.

القرار المعماري الوحيد: صار middleware اسمه proxy

middleware.ts أصبح مهجورًا وتغيّر اسمه إلى proxy.ts، والدالة المصدَّرة middleware صارت proxy. إعادة التسمية يتولّاها الـ codemod.

ما لا يستطيع الـ codemod تولّيه هو القرار الذي تحتها، وهو قرار حقيقي:

بيئة تشغيل edge غير مدعومة في proxy. بيئة تشغيل proxy هي nodejs ولا يمكن ضبطها.

إن كان الـ middleware لديكم يعمل على الحافة - وهذا كان السلوك الافتراضي - فإن إعادة تسمية الملف تنقل ذلك العمل من مئة موقع حافة إلى خادم Node واحد لديكم. بالنسبة لإعادة كتابة مسار أو تحويل لغوي يعمل مع كل طلب، هذا ليس إعادة تسمية، بل تغيير في مصدر زمن الاستجابة.

المسار الموثَّق إن كنتم تحتاجون بيئة الحافة هو الاستمرار على middleware في الوقت الحالي. إذن في الترقية مفترق طرق:

  • عمل توجيه خفيف - إعادة كتابة المسارات، التحويلات، قراءة كوكي - انقلوه إلى proxy واقبلوا بيئة Node.
  • أي شيء حسّاس لزمن الاستجابة على الحافة - ابقوا على middleware حتى تصدر الإرشادات التالية، مع العلم أنكم على اصطلاح مهجور.

في الحالتين، هذه هي اللحظة المناسبة للتحقق إن كان الـ matcher صحيحًا أصلًا في يوم من الأيام. الـ middleware يعمل مع كل طلب، بما فيها تلك التي نسيتموها - وكل واحد من تلك الطلبات صار الآن رحلةً إلى المصدر لديكم.

وتُعاد تسمية أعلام الإعداد معه: skipMiddlewareUrlNormalize صار skipProxyUrlNormalize. هذه يتولّاها الـ codemod.

ما يفشل بصوت عالٍ، فلا تستطيعون نشره

إعداد webpack مع next build. صار Turbopack الافتراضي لـ next build أيضًا، لا لـ next dev وحده، والمشروع الذي فيه إعداد webpack خاص يُفشل البناء عمدًا بدل تجاهله بصمت. ثلاثة مخارج: البناء بـ --turbopack مع تجاهل الإعداد، أو نقله إلى خيارات Turbopack، أو الانسحاب بـ --webpack. ومن المفيد معرفته: قد تكون إضافة برمجية هي التي تضيف خيار webpack لم تكتبوه أنتم، وهذه هي النسخة المربكة من هذا الخطأ.

المسارات المتوازية بلا default.js. صار كل slot يتطلّب ملف default.js صريحًا، ويفشل البناء بدونه. ملفٌّ يستدعي notFound() أو يُعيد null يستعيد السلوك السابق.

Node 18. الحدّ الأدنى صار Node 20.9، و TypeScript 5.1. وأهداف المتصفحات انتقلت إلى Chrome و Edge و Firefox بإصدار 111+ و Safari 16.4+.

next lint و AMP وإعدادات وقت التشغيل. كلها أُزيلت. لم يعد serverRuntimeConfig و publicRuntimeConfig موجودَين - استخدموا متغيّرات البيئة. وnext/legacy/image مهجور، وكذلك images.domains الذي حلّ محلّه remotePatterns.

ما يتغيّر بصمت، وهو الجزء الذي يحتاج تخطيطًا

تخزين الصور المؤقّت انتقل من 60 ثانية إلى 4 ساعات. صارت قيمة images.minimumCacheTTL الافتراضية 14400. لا شيء يرمي خطأً. وإن كنتم تعتمدون على القيمة القديمة لتحديث صور تتغيّر خلال اليوم، فهي لم تعد تتحدّث - والعَرَض صورة قديمة لا يستطيع أحد إعادة إنتاجها لأن ذاكرة المتصفح لديه تخالف ذاكرة المُحسِّن. أعيدوا ضبطها صراحةً إن كنتم تحتاجونها:

// next.config.ts
images: { minimumCacheTTL: 60 },

next build لم يعد يشغّل الـ lint. إن كان خطّ التكامل لديكم يعتمد على البناء لالتقاط أخطاء الـ lint، فقد توقّف عن ذلك بهدوء. كما أن @next/eslint-plugin-next صار يعتمد flat config افتراضيًا. شغّلوا ESLint أو Biome كخطوة مستقلة، وتحقّقوا من وجود تلك الخطوة قبل أن تفترضوا أنها تمرّ.

قيم srcset الافتراضية للصور تغيّرت. حُذف 16 من مصفوفة imageSizes الافتراضية، وتغيّرت قيمة qualities الافتراضية. لا يرمي أيٌّ منهما خطأً، وكلاهما يغيّر ما يُولَّد، وبالتالي ما يُخزَّن ويُقدَّم.

الصور المحلية مع سلسلة استعلام صارت تحتاج إعدادًا. /photo?v=1 يتطلّب مدخلًا في images.localPatterns مع search مطابق. هذا يرمي خطأً فعلًا - لكن على المسارات التي تستخدم النمط فقط، وقد لا تكون هي التي في اختباركم السريع.

الترتيب الذي ينجح

  1. اقرأوا الدليل قبل الـ codemod. يوجد في node_modules/next/dist/docs/ ابتداءً من 16.2، مطابقًا للإصدار المثبَّت فعلًا لا لما تتذكّره الإنترنت.
  2. شغّلوا codemod الترقية، ثم codemod واجهات الطلب غير المتزامنة منفصلًا إن كانت لديكم params أو searchParams أو cookies() أو headers() أو draftMode() متزامنة من فترة توافق الإصدار 15. فـ codemod الترقية لا يشغّل كل عمليات الترحيل.
  3. احسموا مسألة proxy عن قصد، لأن لا شيء سيسألكم عنها.
  4. قارنوا مخرجات البناء بالقديمة. أي المسارات وأيّها ƒ ينبغي ألّا يكون قد تغيّر، وإن تغيّر فالأمر يستحق الفهم قبل النشر.
  5. راجعوا القائمة الصامتة أعلاه مقابل إعداداتكم أنتم.

إن كنتم متأخّرين عدّة إصدارات

الخطوة من 15 إلى 16 محتملة. أما القدوم من 13 أو 14 مع Pages Router ما زال في الشجرة فمشروع آخر، والخطأ هو معاملته كترقية واحدة. الترحيل دون تجميد المزايا يشرح الترتيب الذي يُبقي التطبيق قابلًا للنشر أثناء ذلك، و الترحيل والإنقاذ هو هذا العمل ننفّذه نحن.

العودة إلى كل المقالات