تم إصدار Next.js 9.0 منذ حوالي شهرين. ومنذ ذلك الحين، كنا مشغولين بإصدار 7 إصدارات أصغر ولكنها مهمة جدًا: 9.0.1، 9.0.2، 9.0.3، 9.0.4، 9.0.5، 9.0.6، و 9.0.7.
دعونا نتعمق في ما قدمته هذه الإصدارات لمواقعك وتطبيقاتك، دون أي تغييرات تعطيلية.
- تحسين التزامن في بيئات ويندوز: أصبحت عملية
next build
أكثر موثوقية على ويندوز ويمكنها موازنة العمل بشكل أفضل. - ضغط Gzip افتراضيًا: تمت إضافة ضغط Gzip افتراضيًا لتقليل خطوات التحسين المطلوبة.
- تقرير TypeScript للصفحات النشطة فقط: تم توسيع دعم TypeScript المدمج لمراقبة التغييرات على الصفحات النشطة فقط مما يجعله أسرع وأكثر موثوقية.
- القياس عن بعد (Telemetry): سيساعدنا على التركيز على أجزاء Next.js التي تحتاج إلى تحسين والتحقق من تأثير التحسينات.
- تحسين تتبع عناصر
next/head
: تمت إزالة فئةnext-head
مما يسهل تنفيذ بعض الأدوات التي تتحقق من تنفيذها. - منع الملفات غير الصفحات في دليل الصفحات: تحسين أمان التطبيق ووقت
next build
عن طريق منع النشر العرضي لملفات غير الصفحات. - تحسينات وقت التشغيل: عندما لا يتم استخدام أجزاء معينة من Next.js، مثل
next/dynamic
، لن تكون مطلوبة في وقت التشغيل، مما يجعل أحجام الحزم أصغر.
تحسين التزامن في بيئات ويندوز
يقوم Next.js بعمل متزامن في العديد من الأماكن أثناء عملية next build
. الاستخدام الرئيسي هو تصغير ناتج البناء باستخدام Terser بالتوازي.
سابقًا، تم التعامل مع هذا العمل عبر العديد من وحدات المعالجة المركزية باستخدام حزمة تسمى worker-farm
. ومع ذلك، لاحظنا أن العديد من مستخدمي ويندوز قد قاموا بتعطيل التصغير باستخدام تكوين webpack مخصص. عند الفحص الدقيق، وجدنا أن worker-farm
لم يعمل بشكل متسق على أجهزة ويندوز.
لحل هذه المشكلة، قمنا بالانتقال من worker-farm
إلى jest-worker
. وهذا يضمن أن عمليات البناء موثوقة ومتسقة على أجهزة macOS وLinux وويندوز على حد سواء.
jest-worker
، كما يوحي اسمه، هو جزء من عداء اختبارات Jest. إنها الحزمة التي يستخدمها Jest لموازنة حالات الاختبار. هذا يعني أن هذه الحزمة تم اختبارها جيدًا، وهي موثوقة ويتم صيانتها.
يدعم jest-worker
أيضًا worker_threads
، وهي ميزة جديدة في Node 12. على عكس child_process
، يمكن لـ worker_threads
مشاركة الذاكرة - وهذا يعني أوقات بناء أسرع على إصدارات Node الجديدة.
عن طريق التبديل إلى jest-worker
، تمكنا من إعادة تمكين التزامن في البناء لمستخدمي ويندوز.
ضغط Gzip افتراضيًا
أثناء التحقيق في سبب استخدام الشركات لخادم مخصص، وجدنا أنه في أغلب الأحيان كان للضغط. كانت الشركات تضيف وسيط Express يسمى compression
، والذي يتعامل مع ضغط Gzip لاستجابات HTTP.
هذا الوسيط يضغط الاستجابات بحيث يتم إرسال وحدات بايت أقل عبر الشبكة إلى المستخدمين. عادةً، يجب أن يتم التعامل مع هذا بواسطة وكيل عكسي مثل Nginx. تقوم الوكائل العكسية بإزالة العمل الثقيل على وحدة المعالجة المركزية من عملية Node أحادية الخيط.
ومع ذلك، عند فحص استخدام Next.js على الويب، وجدنا أن نسبة كبيرة من الشركات لم يكن لديها أي ضغط مُهيأ.
على منصات مثل Vercel، يتم التعامل مع gzip
و brotli
تلقائيًا على مستوى الوكيل.
عند الاستضافة الذاتية، يتعين على الشركات إضافة gzip (عبر compression
أو وكيل عكسي) بأنفسهم.
بدءًا من Next.js 9.0.4، يتم تضمين ضغط gzip
افتراضيًا عند استخدام next start
أو server.js
مخصص.
سيتم دعم brotli
قريبًا حيث يدعم Node.js الآن Brotli بشكل أصلي.
إذا كان الضغط مفعلًا بالفعل في تطبيقك عبر خادم مخصص، فلن يضيف Next.js ضاغطه الخاص.
لا يتضمن Next.js الضغط لهدف serverless افتراضيًا لأنه عند استخدام هدف serverless يتم تحميل الأصول بشكل منفصل ولا يتم تقديمها عبر Node.js.
إذا كنت تقوم بالنشر على منصة تتعامل مع الضغط مثل Vercel فلا حاجة لإجراء أي تغييرات.
تقرير TypeScript للصفحات النشطة فقط
تضمن Next.js 9 دعمًا مدمجًا لـ TypeScript. كل ما هو ضروري هو إعادة تسمية صفحة واحدة من .js
إلى .tsx
. سيتعامل Next.js تلقائيًا مع أي إعدادات متبقية أو يرشدك خلالها.
يتعامل Next.js أيضًا مع التحقق من النوع عن طريق تشغيل tsc --watch
بالتوازي مع عملية التطوير. أثناء التطوير، لدى Next.js مفهوم يسمى الإدخلات عند الطلب (on-demand entries). تقوم هذه الميزة بتجميع الصفحات التي تعمل عليها بنشاط فقط.
تدفق الإدخلات عند الطلب
بدءًا من 9.0.4، يقوم Next.js الآن بالإبلاغ عن أخطاء النوع للصفحات التي يتم تجميعها بنشاط بواسطة الإدخلات عند الطلب فقط. هذا يقلل من الكثير من ضوضاء التحقق من النوع أثناء التركيز على مجموعة محددة من الصفحات.
لا يزال التحقق من نوع التطبيق بالكامل يتم تشغيله أثناء next build
أو يمكن التعامل معه في/بواسطة محررك.
القياس عن بعد (Telemetry)
تم إصدار Next.js منذ ما يقرب من 3 سنوات، وقد نما الإطار بشكل كبير في هذه السنوات الثلاث، من ميزات جديدة إلى إعدادات افتراضية أفضل لجميع المستخدمين.
لقد كانت الطريقة التي نتعامل بها مع عملية التحسين هذه يدوية إلى حد كبير.
تمتلك Vercel بعض تطبيقات Next.js الكبيرة. على سبيل المثال، vercel.com، vercel.com/docs، و https://nextjs.org. لقد كنا نستخدم Next.js داخليًا في Vercel وقمنا بتحسين Next.js بناءً على تجاربنا.
بالإضافة إلى ذلك، نتفاعل بنشاط مع المجتمع لجمع التعليقات. من المحتمل أنك تحدثت مع Tim من قبل لتقديم تعليقات حول كيفية استخدامك لـ Next.js في شركتك.
على سبيل المثال، إذا كنت تستخدم خادمًا مخصصًا، أو إذا كان لديك تكوين webpack مخصص، والمزيد. هذه التعليقات لا تقدر بثمن في توجيه تطوير الميزات لـ Next.js.
ومع ذلك، هناك مشكلة في هذا النهج، وهي أنه يمكننا فقط جمع التعليقات من مجموعة فرعية من المستخدمين. قد يكون لهذه المجموعة الفرعية احتياجات وحالات استخدام مختلفة عنك / عن شركتك.
مثال على ذلك هو استيراد ملفات CSS، وهو غير قياسي، ولكن يبدو أن جزءًا كبيرًا من المستخدمين يستخدمون هذا، إما عبر next-css
(أو Sass/Less)، أو تكوين مخصص. إذا عرفنا النسبة المئوية للمستخدمين الذين يستخدمون هذا النهج المحدد، فيمكننا تحديد أولوية تحسينه.
لهذا السبب، قدمنا نهجًا مجهولًا وأكثر تلقائية لجمع نقاط التعليقات هذه حتى نتمكن من تحسين Next.js أكثر في المستقبل القريب.
سيسمح لنا هذا أيضًا بالتحقق مما إذا كانت التحسينات التي تم إجراؤها على الإطار تعمل على تحسين الأساس لجميع التطبيقات.
يمكنك قراءة المزيد عن القياس عن بعد على nextjs.org/telemetry. ستجد هناك أيضًا كيفية الاختيار للانسحاب إذا كنت لا ترغب في المشاركة.
تعليقات البناء مع نقاط تشير إلى النشاط
أثناء التحدث إلى مستخدمي Next.js، كانت إحدى التعليقات الصغيرة هي أنه بدا أحيانًا أن next build
لا يفعل أي شيء، خاصة بصريًا.
لحل هذا، أضفنا مؤشر تحميل إلى ناتج وحدة التحكم أثناء تشغيل next build
. يعطي هذا الناتج مؤشرًا مرئيًا على أن الأمر لا يزال قيد التشغيل، وأن العملية لا تتجمد.
نخطط لتوسيع ناتج البناء هذا لإظهار المزيد من مراحل البناء عندما يكون ذلك ممكنًا.
نقاط مؤشر البناء الجديدة
تحسين تتبع عناصر next/head
يوفر Next.js طريقة مدمجة لإدارة عناصر <head>
لأنه مسؤول عن عرض HTML لتطبيقك. يتم عرض واجهة برمجة التطبيقات هذه عبر وحدة next/head
.
على سبيل المثال، لإضافة عنوان إلى الصفحة:
import Head from 'next/head';
export default function MyPage() {
return (
<>
<Head>
<title>My Title</title>
</Head>
<h1>Hello World</h1>
</>
);
}
عند العرض إلى HTML، سيجمع Next.js جميع المكونات المعروضة داخل <Head>
ويعرض العلامات في <head>
لصفحتك.
ومع ذلك، يسمح Next.js بانتقالات المسار من نوع تطبيق الصفحة الواحدة (SPA) باستخدام مكون <Link>
.
عند النقر على <Link>
، سيقوم Next.js بجلب ملف JavaScript المطلوب لعرض الصفحة على جانب العميل. ثم سيعرض مكون React المرتبط بالملف.
لأن هذا الانتقال يحدث على جانب العميل، يتعين علينا تنظيف عناصر <head>
المحقونة من الصفحة السابقة، وإلا فقد تظهر عناصر قديمة على صفحة أخرى.
سابقًا، كان Next.js يتتبع هذه العناصر عن طريق إضافة اسم فئة لكل عنصر يتم توفيره بواسطة <Head>
.
بأخذ المثال أعلاه، سيبدو <head>
كما يلي:
<head>
<title class="next-head">My Title</title>
</head>
يعمل هذا الحل جيدًا حيث تم تمييز كل عنصر تم حقنه عبر next/head
بوضوح وكان من السهل تنظيفه.
ومع ذلك، أبلغ عدد قليل من المستخدمين عن مشاكل أن سمة class
الإضافية على العناصر تجعل البرامج النصية المضافة من خدمات خارجية لا تمرر التحقق.
قام Gerald Monaco، من فريق Google Chrome، بابتكار طريقة للحفاظ على سلوك التنظيف دون الحاجة إلى اسم فئة على العناصر.
السلوك الجديد هو أن Next.js سيقوم بإدراج علامة <meta>
إضافية تحمل عدد العناصر التي قام (next/head
) بعرضها. باستخدام هذا، يمكن لـ Next.js استخدام العدد لتنظيف العناصر الموجودة.
نتيجة لذلك، يقلل هذا النهج من حجم حمولة HTML الأولية عند حقن عناصر متعددة في <head>
للصفحة.
منع الملفات غير الصفحات في دليل الصفحات
عند البدء باستخدام Next.js، أول شيء تقوم به هو إنشاء دليل pages
.
الاتفاقية هي أن كل ملف في دليل pages
يصبح مسارًا في التطبيق. مثال بسيط هو أن pages/about.js
يصبح /about
.
مع مرور الوقت، تلقينا تقارير عرضية تفيد بأن تطبيقات المستخدمين، الكبيرة والصغيرة، كان أداء بنائها ضعيفًا.
عند الفحص الدقيق، تبين أن هؤلاء المستخدمين قاموا بإنشاء هيكل مكوناتهم بالكامل في دليل pages
.
نظرًا لأن كل ملف في دليل pages
يعامل كصفحة، كان يتم تجميع كل مكون كصفحة في التطبيق. هذا يسبب الكثير من الحمل الزائد لوقت البناء، مما يولد 2+ ملفات JavaScript لصفحات غير صالحة.
علاوة على ذلك، سيؤثر هذا جزئيًا على كيفية قرر Next.js إنشاء أجزاء تقسيم الكود. هذا لأن Next.js يستخدم إرشادات حول استخدام المكتبة عبر الصفحات.
بسبب هذا، يجب علينا التأكد من أن المستخدمين لا يقدمون هذا المأزق إلى تطبيق Next.js الخاص بهم.
يقوم Next.js 9 الآن بالتحقق من أن الملفات داخل دليل pages
تصدر مكون React.
في العمل، هذا يعني أن Next.js سيعرض لك رسالة تنبهك إلى أنه تم العثور على ملف غير صفحة محتمل في دليل pages
.
يشجع هذا المستخدم على نقل الملف الذي ليس صفحة إلى دليل آخر. في المقابل، يكون التطوير والإنتاج وتقسيم الكود أسرع وأكثر دقة.
تحسينات وقت التشغيل
يتكون إطار عمل Next.js من العديد من الأجزاء. أحدها هو وقت التشغيل على جانب العميل. يتعامل وقت التشغيل هذا مع الترطيب (hydration)، وتوجيه جانب العميل، والمزيد.
الترطيب، وهو ما ركز عليه هذا التحسين، هو ما يلزم لجعل HTML المعروض على الخادم أو المعروض مسبقًا تفاعليًا. يضيف الترطيب معالجات الأحداث ويستدعي طرق دورة الحياة مثل useEffect()
أو componentDidMount
- مما يجعل تطبيقك جاهزًا للمستخدم النهائي.
علاوة على ذلك، يتعامل Next.js مع أكثر من الترطيب الأساسي - على سبيل المثال، إعداد موجه جانب العميل، وتكوين next/head
، وتحميل منطق التطبيق الإضافي عبر next/dynamic
.
كل من هذه المسؤوليات لها جزء وقت تشغيل خاص بها أيضًا.
في حالة next/dynamic
، يتعين على Next.js التأكد من أن المكونات المحملة بكسل والتي تم عرضها على الخادم جاهزة على جانب العميل. كل استخدام لـ next/dynamic
يولد حزمة JavaScript إضافية، ويجب تحميل هذه الملفات قبل الترطيب لتجنب عدم تطابق الترطيب.
سابقًا، كان وقت التشغيل هذا مدرجًا في حزمة وقت تشغيل Next.js دائمًا. الآن، يتم تضمينه فقط عند استخدام next/dynamic
في تطبيقك. هذا يعني تنزيل وتحليل وتنفيذ كود JavaScript أقل للتطبيقات التي لا تستخدم next/dynamic
.
دعم AppTree
تطبق بعض المكتبات في نظام React البيئي عرض جانب الخادم بطريقة محددة جدًا. الأكثر شهرة، حل عرض جانب الخادم لـ Apollo، المسمى getDataFromTree
، يعمل عن طريق عرض شجرة React ولكل Query
يتم العثور عليه سينتظر النتيجة ثم يعيد عرض شجرة React مرة أخرى.
افتراضيًا، يضيف Next.js بعض قيم السياق إلى شجرة React، على سبيل المثال، الموجه الذي يمكن قراءته باستخدام useRouter
.
كانت الطريقة التي كان يستخدمها مثال with-apollo
لعرض شجرة React هي عن طريق عرض <App>
ومحاولة ملء الخصائص المفقودة يدويًا. مع إضافة React Context لم يعد هذا ممكنًا لأن موفر السياق هو عنصر منفصل.
بدءًا من Next.js 9.0.4 تمت إضافة خاصية جديدة تسمى AppTree
إلى كائن السياق في getInitialProps
. تمت إضافتها خصيصًا للحالات التي يتعين فيها على المكتبات الخارجية اجتياز شجرة React بالكامل مثل getDataFromTree
لـ Apollo.
تم تحديث مثال with-apollo
ليعكس التغييرات. إذا كان لديك Apollo مطبق بالفعل في تطبيقك فمن المستحسن التحديث إلى نهج AppTree
بحيث تعمل useRouter
وواجهات برمجة التطبيقات الأخرى المضافة في المستقبل بشكل صحيح في تطبيق Next.js الخاص بك.
إذا كنت لا تستخدم Apollo أو مكتبة مشابهة نوصي بمحاولة تجنب استخدام AppTree، حيث لا يوصي فريق Next.js باجتياز شجرة React بشكل عام. يضيف هذا الكثير من الحمل الزائد للأداء لأن شجرة React يتم عرضها عدة مرات بدلاً من مرة واحدة فقط.
إزالة حزمة next-server
عندما بدأنا في تحسين Next.js لنشرات السيرفرليس (serverless) منذ أكثر من عام، أنشأنا حزمة تسمى next-server
. كانت هذه الحزمة تجريبية ونُشرت جنبًا إلى جنب مع حزمة next
. لم يتم توثيقها علنًا أبدًا ولكنها كانت تجربة لإنشاء أصغر وقت تشغيل لخادم Next.js ممكن.
في النهاية، نجحت الحزمة وجعلت وقت تشغيل الخادم للإنتاج أصغر. ومع ذلك، توصلنا إلى طريقة جديدة مبتكرة لجعل وقت التشغيل أصغر باستخدام مترجم Next.js والتحليل الثابت (static analysis).
وبذلك، أصبحت next-server
قديمة واستُبدلت بـهدف السيرفرليس (serverless target). هذا الهدف لديه إخراج مُحسّن بشكل أكبر من استخدام حزمة next-server
كبديل لـ next
.
على الرغم من أن هذه الحزمة كانت قديمة ولا يمكن استخدامها مباشرة، إلا أننا احتفظنا بها. وذلك لأنها كانت تحتوي على أجزاء داخلية مشتركة بين الحزم ونقل الكود كان سيتطلب جهدًا غير بسيط.
لقد بذلنا هذا الجهد مؤخرًا ونقلنا الكود من next-server
مرة أخرى إلى حزمة next
. مما يعني أن جميع أكواد إطار عمل Next.js موجودة الآن في حزمة next
.
هذا يجعل الأمر أسهل للمبتدئين والمساهمين المخضرمين على حد سواء للمساهمة في Next.js. هناك الآن عملية تجميع واحدة وتكوين بناء موحد. سابقًا، كانت هناك إعدادات منفصلة لـ next
و next-server
، إلى جانب قيود تعسفية على الكود الذي ينتمي إلى كل حزمة.
ترقية Next.js
إذا كان مشروعك يعمل على إصدار قديم من Next.js، نوصي بالترقية إلى Next.js 9.
في معظم الحالات، لا يلزم إجراء أي تغييرات للترقية. يمكنك اتباع دليل الترقية لضمان تجربة ترقية سلسة.
نود أن نشكر جميع المساهمين من المجتمع الذين قاموا بتحديث الدليل منذ إصداره.
ما الجديد في المستقبل؟
تحسينات الجديدة المذكورة في هذه المدونة هي مجرد بداية لتحسينات وميزات أوسع نعمل عليها.
سنشارك تحديثًا حول طلبات التعليقات (RFCs) الجارية قريبًا جدًا. حتى ذلك الحين، يمكنك الحصول على لمحة صغيرة من خلال علامة RFC على GitHub.
هذا يوضح بعض الميزات التي كنا نبحث فيها مثل دعم CSS المدمج (built-in CSS support)، دعم دليل public (public directory support)، ودعم دليل src (src directory support).
المجتمع
نحن متحمسون لرؤية النمو المستمر لمجتمع Next.js.
- كان لدينا أكثر من 800 مساهم قاموا بإدخال commit واحد على الأقل.
- على GitHub، تم تصنيف المشروع بأكثر من 41,100 نجمة.
لقد تضاعف مجتمع Next.js منذ الإصدار الرئيسي الأخير مع أكثر من 10,900 عضو. انضم إلينا!
نحن متحمسون للمساهمات المستمرة من المجتمع والملاحظات الخارجية من الشركات والمستخدمين التي تساعد في تشكيل الإصدارات.