Backالعودة إلى المدونة

Turbopack Dev أصبح الآن مستقرًا

لقد كانت رحلة طويلة، لكننا سعداء بالإعلان عن أن `next dev --turbo` أصبح الآن مستقرًا وجاهزًا لتعزيز تجربة التطوير الخاصة بك.

لقد كانت رحلة طويلة، لكننا سعداء بالإعلان عن أن next dev --turbo أصبح الآن مستقرًا وجاهزًا لتعزيز تجربة التطوير الخاصة بك. لقد كنا نستخدمه للتكرار على vercel.com، nextjs.org، v0، وجميع تطبيقاتنا الأخرى بنتائج رائعة.

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

استثمرنا الكثير من الوقت والجهد في تحسين webpack، ولكن في مرحلة ما، شعرنا أننا لا نحصل على تحسين كافٍ مقابل الجهد المبذول. كنا بحاجة إلى أساس جديد يمكنه دعم العديد من تطبيقات Next.js الموجودة بالفعل في الإنتاج اليوم، بالإضافة إلى الابتكارات المستقبلية التي خططنا لها، مثل مكونات خادم React (React Server Components).

كانت هذه متطلباتنا لهذا المجمع الجديد:

  • أقل قدر ممكن من التغييرات الكاسرة
  • دعم كل من موجه التطبيق (App Router) وموجه الصفحات (Pages Router)
  • أوقات تجميع أسرع لقواعد الكود بجميع أحجامها
  • عمليات بناء للتطوير تتطابق بشكل وثيق مع الإنتاج
  • تحسينات متقدمة للإنتاج (مثل هز الشجرة داخل الوحدات)
  • رسم بياني للوحدات يدعم بيئات متعددة مثل Node.js والمتصفح
  • قابلية المراقبة الكاملة للمحافظين والمستخدمين المتقدمين

قمنا بتقييم جميع الحلول الموجودة في ذلك الوقت ووجدنا أن كل منها كان لديه مقايضات لا تتوافق مع متطلباتنا وأهدافنا. كان من المنطقي بالنسبة لنا تصميم شيء من البداية يمكنه تحقيق بالضبط ما يحتاجه Next.js اليوم وامتلاك خطة الطريق حتى نتمكن من بناء وتجربة ما سيحتاجه غدًا. كان هذا هو دافعنا لإنشاء Turbopack.

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

  • أسرع بنسبة تصل إلى 76.7% في بدء تشغيل الخادم المحلي.
  • أسرع بنسبة تصل إلى 96.3% في تحديثات الكود مع Fast Refresh.
  • أسرع بنسبة تصل إلى 45.8% في تجميع المسار الأولي دون التخزين المؤقت (لا يمتلك Turbopack تخزينًا مؤقتًا على القرص بعد).

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

أبرز الميزات

تجميع أولي أسرع للمسار

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

لنكون منصفين، تقوم المجمعات مثل webpack بالكثير من العمل تحت الغطاء. عند تجميع مسار لأول مرة، يبدأ المجمع عند "نقطة الدخول". في حالة Next.js، إنها مزيج من page.tsx وجميع الملفات المرتبطة بهذا المسار، مثل layout.tsx و loading.tsx، إلخ. يتم تحليل نقاط الدخول هذه للعثور على عبارات import التي يتم حلها إلى ملفات، والتي تتم معالجتها بعد ذلك بنفس طريقة نقاط الدخول، وتستمر هذه الدورة حتى لا يتم العثور على المزيد من عمليات الاستيراد. تقوم هذه العملية ببناء رسم بياني للوحدات، والذي يمكن أن يتكون ليس فقط من وحدات TypeScript / JavaScript (بما في ذلك node_modules)، ولكن أيضًا ملفات CSS (العالمية ووحدات CSS)، والملفات الثابتة مثل الصور المستوردة لـ next/image.

بعد جمع جميع الوحدات، يتم استخدام الرسم البياني للوحدات لإنشاء حزم من JavaScript، والتي يشار إليها غالبًا باسم "قطع". هذه القطع هي مخرجات المترجم التي تعمل على الخادم (في وقت البناء أو وقت التشغيل) أو في المتصفح.

لا يدعم webpack إنشاء رسوم بيانية تنتج مخرجات لبيئات متعددة، لذلك يتعين علينا تشغيل مترجمين منفصلين على الأقل في Next.js مع webpack اليوم، واحد للخادم وواحد للمتصفح. يجب علينا تجميع الرسم البياني لوحدة الخادم أولاً حتى يمكن العثور على جميع المراجع إلى "use client". بمجرد بناء الخادم، نقوم باجتياز رسمه البياني لإنشاء نقاط الدخول ذات الصلة لمترجم المتصفح. نظرًا لأن هذا مترجم webpack منفصل، فهناك بعض النفقات العامة في هذه العملية، مثل تحليل نفس الكود مرتين عبر العميل والخادم.

مع Turbopack، شرعنا في إزالة النفقات العامة لتشغيل مترجمين متعددين والتنسيق بينهما. كان الحل هو جعل المترجم على دراية بأهداف مخرجات متعددة مختلفة. داخليًا، تسمى هذه "تحولات" الهدف. يمكننا وضع علامة على استيراد كتحول من الخادم إلى المتصفح أو من المتصفح إلى الخادم. هذا ما يسمح لـ Turbopack بتجميع مكونات الخادم ومكونات العميل، وكذلك وظائف الخادم المستوردة من مكونات العميل بكفاءة.

بالإضافة إلى تحسين الأداء، فإن وجود مترجم واحد يمكنه التعامل مع بيئات متعددة في جولة واحدة له فوائد الموثوقية وتصحيح الأخطاء، حيث لم نعد مضطرين للتنسيق بين عمليتي مترجم منفصلتين في Next.js.

الفرق الكبير الآخر بين webpack و Turbopack هو أن Turbopack يمكنه موازنة العمل عبر وحدات معالجة متعددة، بينما مع webpack، تتم موازنة خطوة تحويل TypeScript / JavaScript فقط باستخدام SWC.

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

تمكنا أيضًا من تحقيق انتصارات في الأداء مع عمليات قراءة وكتابة أسرع لنظام الملفات، وحل وحدة أسرع، ومن خلال تخطي المزيد من العمل على الوحدات الخالية من الآثار الجانبية.

عند استخدام Turbopack على vercel.com، وهو تطبيق Next.js كبير، رأينا أسرع بنسبة 45.8% في التجميع الأولي مقارنةً بـ Next.js مع webpack.

Fast Refresh أسرع

Fast Refresh هو النظام الذي تستخدمه المجمعات لنشر التغييرات إلى المسار الذي تنظر إليه حاليًا في المتصفح، والذي يشار إليه أحيانًا باسم استبدال الوحدة الساخن (HMR).

يحتوي Next.js على تكامل أعمق يربط Fast Refresh بـ React، مما يضمن أن React لا يفقد الحالة عندما تقوم بتغيير مكون.

مع webpack، وجدنا أن هناك حدًا لأداء Fast Refresh عندما تصل إلى عدد معين من وحدات JavaScript. يحتاج Webpack إلى اجتياز الرسم البياني وإنشاء مخرجات حتى للوحدات التي لم تتغير، مع التوسع خطيًا مع كمية وحدات JavaScript.

وجدنا أنه عند حوالي 30,000 وحدة، يكون لتغييرات الكود ثانية واحدة على الأقل من النفقات العامة لمعالجة التحديث، بغض النظر عما إذا كان التغيير صغيرًا. على سبيل المثال، قد يستغرق تغيير لون في ملف CSS ثانية واحدة ليظهر على الشاشة.

لم يكن هذا الأداء مقبولًا بالنسبة لنا. نعتقد أن عمليات البناء التدريجية يجب أن تتوسع فقط مع حجم التغييرات المحلية، وليس حجم المسار أو التطبيق. عندما يتغير button.tsx، يجب أن يقوم المترجم فقط بتشغيل العمل المتعلق بتغيير هذا الملف بدلاً من الاضطرار إلى إعادة حساب الوحدات الأخرى وملفات المخرجات التي لا تتأثر بالتغيير. لمكافحة هذا، قمنا بإعطاء الأولوية لأساس في Turbopack يسمح بإعادة حساب دقيقة جدًا للعمل.

تحول هذا الجهد إلى المكتبة الأساسية، Turbo Engine، التي تستخدم بنية حسابية تدريجية مدفوعة بالطلب تلقائيًا لتوفير إعادة تحميل ساخن تفاعلي لتطبيقات Next.js و React الضخمة في عشرات المللي ثانية. تستند هذه البنية إلى أكثر من عقد من البحث والأعمال السابقة، بما في ذلك webpack، Salsa، Parcel، Adapton، ونظام استعلام مترجم Rust.

الآن مع Turbopack، تتوسع سرعة Fast Refresh مع حجم التغييرات الخاصة بك، وهو كيف تمكنا من تحقيق 96.3% أسرع في تحديثات الكود مع Fast Refresh على تطبيقات Next.js كبيرة مثل vercel.com.

تتبع متقدم

مع نمو Next.js في الاعتماد على مر السنين، وجدنا أنه من الصعب بشكل متزايد إعادة إنتاج المشكلات المبلغ عنها على GitHub، خاصة تلك المتعلقة بأداء المترجم واستخدام الذاكرة. هذا لأن معظم الأشخاص لا يمكنهم مشاركة كود تطبيقهم، أو عندما يشاركون الكود، لا يمكن تشغيل التطبيق لأنه يتطلب قاعدة بيانات أو إعداد آخر.

للبدء في معالجة هذا، أضفنا تتبعًا إلى الأجزاء الداخلية لـ Next.js. يتم كتابة هذه التتبعات إلى ملف في مجلد .next ولا تتضمن كود التطبيق - فقط مسار الملف، والوقت الذي استغرقه المترجم عليه، والتوقيتات الفردية مثل التحويلات الفردية. ومع ذلك، مع webpack، لم يكن لدينا أبدًا طريقة جيدة للتمييز بوضوح بين استخدام الذاكرة للمترجم واستخدام الذاكرة لإطار العمل أو كود التطبيق، حيث يعملون جميعًا في نفس مثيل Node.js.

مع Turbopack، تمكنا من التصميم مع أدوات القياس من البداية. قمنا بتنفيذ طبقة أدوات قياس في Turbo Engine تسمح بجمع توقيتات كل وظيفة فردية. تمكنا من توسيع هذه التتبعات لتتبع أيضًا تخصيص الذاكرة، وإلغاء التخصيص، والذاكرة المستمرة عبر كل وظيفة.

يعطينا هذا التتبع الجديد والمتقدم جميع المعلومات اللازمة للتحقيق في التباطؤ واستخدام الذاكرة بعمق؛ فهو يتطلب فقط تتبعًا بدلاً من قاعدة كود كاملة.

من أجل معالجة هذه التتبعات الجديدة، قمنا بتنفيذ عارض تتبع مخصص يظل فعالاً بغض النظر عن حجم التطبيق والتتبع. إنه عارض تتبع مصمم خصيصًا للتحقيق في التباطؤ واستخدام الذاكرة لـ Turbopack وقد سمح لنا بتحسين الأداء عبر العديد من تطبيقات المستخدمين الأوائل لأنه يقصر حلقة التغذية الراجعة.

بينما تم بناء عارض التتبع في البداية للاستخدام الداخلي (وهو مخصص للحالات التي تكون فيها الغوص الفني العميق مطلوبًا)، فقد قمنا بإدراج القطع المطلوبة لتشغيله بنفسك في Next.js. يمكنك إنشاء تتبع Turbopack باستخدام هذه التعليمات. ثم، عند إنشاء التتبع، يمكنك استخدام next internal turbo-trace-server .next/trace-turbopack لبدء الخادم الذي يسمح بفحص التتبع. هناك نظرة سريعة على فيديو عارض التتبع متاح هنا.

تقليل التقلب في أوقات التجميع

عند استخدام Next.js مع webpack، غالبًا ما لا تكون أوقات التجميع شفافة بما فيه الكفاية. في حالة واحدة، قد يستغرق فتح صفحة 10 ثوانٍ، وفي أخرى قد يستغرق 20 ثانية. بينما قد يكون هناك ذاكرة تخزين مؤقت موجودة، إلا أنها أحيانًا لا يكون لها تأثير كافٍ لإنتاج نتائج متسقة. حتى في التجميع بدون ذاكرة تخزين مؤقت، رأينا بعض التباين.

تضمن البنية الأساسية لـ Turbopack أن يكون التباين في أوقات التجميع أكثر اتساقًا. تختلف أوقات تجميع المسارات بنسبة قليلة فقط، مما يسمح لنا بتحسين أداء المترجم باستمرار.

عمليات بناء للتطوير تتطابق بشكل وثيق مع الإنتاج

من أجل التحسين لسرعة التجميع مع webpack، كان علينا قبول بعض المقايضات التي أدت إلى اختلاف بيئات التطوير والإنتاج. بعض الأمثلة على هذه المقايضات هي أننا نستخدم style-loader، الذي يحقن النمط في الصفحة ويسمح بـ Fast Refresh لها، دون إعادة تحميل الصفحة. ومع ذلك، هذا يعني أن الأنماط يتم حقنها بواسطة JavaScript في التطوير، مما يتسبب في ومضة من المحتوى غير المنسق. نعمل حول هذه الومضة من المحتوى غير المنسق، لذلك لا تراها. مثال آخر هو أن Next.js مع webpack يستخدم eval-source-map، مما يعني أن جميع الأكواد ملفوفة في eval وتتم تضمين خرائط المصدر في ذلك، مما يضمن توفر خرائط المصدر في التطوير على حساب صعوبة فحص وتصحيح الكود المجمع. بينما يدعم webpack إخراج خرائط مصدر كاملة باستخدام خيار source-map، فإنه يتسبب في تأثير كبير على وقت التجميع واستخدام الذاكرة.

بالنسبة لـ Turbopack، شرعنا في حل هذه المشكلات افتراضيًا، وإخراج ملفات CSS وخرائط المصدر دون استخدام eval. يستفيد Turbopack من خرائط مصدر sections، وهو جزء جديد نسبيًا من مواصفات خريطة المصدر التي تسمح بدمج أكثر كفاءة لمخرجات خرائط المصدر. حيث كان علينا سابقًا إنشاء جميع التعيينات في مكان واحد، يمكننا الآن إنشاؤها وتخزينها مؤقتًا بشكل أكثر دقة.

يتعامل Turbopack مع CSS دائمًا بإخراج ملفات CSS، وعلى غرار التعامل مع JavaScript يمكنه تحديث ملف CSS دون تحديث المتصفح بواسطة آلية هي جزء من وقت تشغيل تطوير Turbopack.

يمكننا الآن أن نقول بثقة أنه عندما يعمل شيء ما في التطوير مع Turbopack، فإنه يعمل ويتصرف بنفس الطريقة في الإنتاج.

إصدارنا المستقر الأول

قبل عامين، قدمنا Turbopack كإصدار ألفا مع Next.js 13، مما يوفر معاينة لإمكانات أدائه. بينما كانت النتائج الأولية واعدة، إلا أنها كانت تدعم فقط الاستخدام الأساسي - لم يتم تنفيذ العديد من ميزات Next.js، مثل basePath.

خلال العام التالي، ركزنا على إضافة ميزات Next.js والتجميع المفقودة. بناءً على ملاحظات المجتمع، قررنا التركيز بالكامل على تجربة next dev حتى نتمكن من معالجة الشكاوى الأكثر شيوعًا حول سرعة التكرار. بحلول مؤتمر Next.js العام الماضي، كانت 90% من اختبارات التطوير تمر، وكان مطورو Vercel يستخدمون بالفعل Turbopack في التطوير اليومي.

في أبريل، أعلنا عن Next.js 14.2 مع نجاح 99.8% من الاختبارات، ووصلنا إلى 100% بعد ذلك بوقت قصير. منذ ذلك الحين، قمنا بمعالجة المشكلات المبلغ عنها على GitHub، خاصة حول حزم npm، و Fast Refresh، ودقة موقع الخطأ.

باعتراف الجميع، استغرق الطريق إلى الاستقرار وقتًا طويلاً، لكن هذا يعود في الغالب إلى مجموعة اختبارات Next.js الواسعة، التي تحدد معيارًا عاليًا للاستقرار. كان لدينا 8 سنوات لاكتشاف الحالات الطرفية وإضافة 6,599 اختبار تطوير كان لا بد أن تمر أيضًا مع Turbopack. عامل إضافي هو أننا صممنا Turbopack ببنية مختلفة تمامًا عن webpack. كان من الأسهل ببساطة نقل webpack إلى Rust ولكنه لن يفتح انتصارات الأداء التي نريد تحقيقها.

الآن بعد أن اجتاز Turbopack جميع الاختبارات، وتم التحقق منه مع أفضل حزم npm، وتمت معالجة ملاحظات المستخدمين الأوائل، نحن مستعدون لاعتباره مستقرًا.

ما الذي يعتبر مستقرًا بالضبط؟

كان هذا نقطة ارتباك في الماضي، لذا سنخصص هذا القسم لتوضيح ما يوفره هذا الإصدار لمجتمع Next.js.

هذا الإصدار يحدد بشكل خاص أمر next dev --turbo على أنه مستقر. عمليات البناء للإنتاج (next build --turbo) غير مدعومة بعد، ولكن تابع القراءة للحصول على تحديث حيث أنها قيد التقدم. نخطط في النهاية لإصدار نسخة مستقلة من Turbopack خارج Next.js، ولكننا نريد إثبات جدارته من خلال تحسين تجربة مجتمع Next.js أولاً.

بخلاف الميزات غير المدعومة التي سنغطيها في القسم التالي، يجب أن يعمل Turbopack مع جميع الميزات المستقرة في Next.js. للتوضيح، يدعم Turbopack كلًا من "موجه التطبيق (App Router)" و"موجه الصفحات (Pages Router)". قد تعمل الميزات التجريبية مع Turbopack أو لا تعمل، ولكنها بالتأكيد ستعمل بحلول الوقت الذي يتم تحديدها فيه كميزات مستقرة.

إذا كان تطبيقك يحتوي على تخصيصات لـ webpack ولكن يضيف فقط "حملات (loaders)" لـ webpack، فقد تتمكن بالفعل من استخدام Turbopack عن طريق تكوين الحملات لـ Turbopack. يمكنك قراءة الوثائق لدعم حملات webpack في Turbopack.

إليك قائمة بحملات webpack التي تم التحقق من عملها مع Turbopack:

  • @svgr/webpack
  • babel-loader
  • url-loader
  • file-loader
  • raw-loader
  • tsconfig-paths-webpack-plugin — مدعومة مباشرة دون الحاجة إلى إضافة.
  • معظم الحملات الأخرى تعمل أيضًا، حيث ندعم مجموعة فرعية من واجهة برمجة تطبيقات حملات webpack.

معظم مكتبات CSS و CSS-in-JS مدعومة:

  • مدعومة
    • Tailwind CSS
    • @emotion/react
    • Sass
    • styled-components
    • Bootstrap
    • Antd
    • node-sass
    • JSS
    • Emotion
    • theme-ui (يستخدم Emotion)
    • @chakra-ui/core (مع Emotion)
    • aphrodite
  • غير مدعومة حاليًا
    • Less — يمكنك إضافة less-loader. Next.js مع webpack لا يدعم Less مباشرة أيضًا.
    • @vanilla-extract/css — يستخدم إضافة مخصصة لـ webpack — سنبحث في كيفية دعم الخطوط المطلوبة في المستقبل.
    • StyleX — يتطلب تحويل Babel ودعم لسمات data: — سنبحث في دعم StyleX بعد استقرار next build --turbo.

الأداء

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

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

خلال الأشهر الثلاثة الماضية، قمنا بالفعل بإجراء بعض التحسينات الكبيرة. مقارنة Turbopack في Next.js 15 RC 2 مقابل Turbopack في 15 RC 1 تظهر نتائج هذه التحسينات:

  • انخفاض متوسط في استخدام الذاكرة بنسبة 25-35%.
  • تجميع أولي أسرع بنسبة 30-50% للصفحات الكبيرة التي تحتوي على آلاف الوحدات.

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

تغييرات غير متوافقة

كانت الحافز الكبير لبناء أداة تجميع خاصة بنا هو الحاجة إلى مطابقة السلوكيات الحالية لـ webpack قدر الإمكان، وهو شيء لم نتمكن من ضمانه مع أي حل موجود في ذلك الوقت. وهذا يشمل طريقة حل الملفات وميزات أصغر لـ webpack، مثل تعليق webpackIgnore الذي تستخدمه بعض حزم npm.

لسوء الحظ، كان علينا إزالة بعض الميزات من أجل ضمان مستقبل Turbopack والتطبيق المرتبط بـ Next.js. ستظل هذه الميزات مدعومة عند استخدام webpack.

هناك بعض النقاط البارزة، دعونا نتعمق في الأسباب التي جعلتنا نغيرها:

تكوين webpack() غير مدعوم. Turbopack ليس webpack، ليس لديه نفس هيكل خيارات التكوين، على الرغم من أنه يدعم العديد من الميزات نفسها. على وجه التحديد قمنا بتنفيذ دعم لحملات webpack و الأسماء المستعارة للحل (resolve aliases). معظم حملات webpack التي تقوم بتحويل التعليمات البرمجية مدعومة مباشرة. بعض حملات webpack التي تقوم بأشياء غريبة، مثل مترجم فرعي لـ webpack وإنشاء ملفات، غير مدعومة.

.babelrc لن يحول التعليمات البرمجية تلقائيًا. يستخدم Turbopack SWC افتراضيًا. لا يزال بإمكانك إضافة babel-loader حسب الحاجة، ولكننا نضمن أن الإعدادات الافتراضية سريعة دائمًا وأنها منطقية من حيث البنية أيضًا. يتعين علينا دائمًا تشغيل SWC، حتى إذا قمت بتكوين .babelrc، لمعالجة التحسينات الأخرى. هذا مشابه لكيفية اضطرار webpack دائمًا إلى تشغيل محلل acorn لإجراء مزيد من التحسينات. إذا كنت تستخدم SWC بدلاً من Babel مع Turbopack، فيمكننا التحليل مرة واحدة والاستفادة من نفس شجرة البنية المجردة (AST) من البداية إلى النهاية عبر Turbopack.

بعض ميزات وحدات CSS الأقل استخدامًا. قمنا بتحويل معالجة CSS من PostCSS إلى Lightning CSS. Lightning CSS هو مترجم CSS أسرع بكثير يدعم تحويلات CSS، تصغير الحجم، ووحدات CSS مباشرة. المقايضة هي أن بعض الميزات الأقل استخدامًا غير مدعومة. على وجه التحديد محددات الزائفة :global و :local (لا تزال متغيرات الدالة :global() و :local() تعمل)، @value، وقواعد ICSS :import / :export. كما أنه أكثر صرامة من محللات CSS الأخرى وسيشير إلى الأخطاء في التعليمات البرمجية بدلاً من تجاهلها.

في عملية إضافة Lightning CSS، ساهمنا مرة أخرى في المشروع. على سبيل المثال، قمنا بتنفيذ خيارات دقيقة لوحدات CSS لتعطيل بادئات شبكة CSS ووضع pure لوحدات CSS. هذا يسهل اعتماد Lightning CSS لوحدات CSS عند الانتقال من css-loader في webpack. كما أننا قمنا بتحسين الأخطاء لميزات وحدات CSS غير المدعومة.

نحن ممتنون لـ ديفون جوفيت، المؤلف والمسؤول عن Lightning CSS، للتعاون المستمر على المشروع.

الميزات التجريبية. نظرًا لأننا نركز على استقرار Turbopack في Next.js، قررنا التركيز أولاً على الميزات المستقرة المتاحة في Next.js.

للحصول على القائمة الكاملة، راجع صفحة الوثائق.

خارطة الطريق

لقد قطع Turbopack شوطًا طويلاً، ولكن لا يزال هناك الكثير من العمل الذي يتعين القيام به. الميزتان المثيرتان القادمتان هما التخزين المؤقت الدائم وعمليات البناء للإنتاج. نتوقع أن يبدو النشر بالترتيب التالي:

  • التخزين المؤقت الدائم — إصدار ثانوي مستقبلي
  • إصدار تجريبي للبناء — إصدار ثانوي مستقبلي
  • مرشح إصدار للبناء — إصدار ثانوي مستقبلي
  • بناء مستقر — إصدار ثانوي مستقبلي
  • موصى به في create-next-app للتطبيقات الجديدة — إصدار ثانوي مستقبلي
  • افتراضي في Next.js عندما لا يكون لديك تكوين مخصص لـ webpack — إصدار رئيسي مستقبلي

بينما سيظل webpack في Next.js، نتوقع أنه بسبب فوائد Turbopack، سترغب غالبية تطبيقات Next.js في استخدامه. بمجرد اكتمال Turbopack لعمليات البناء للإنتاج، سنبدأ العمل على دعم إضافات webpack الشائعة الاستخدام.

لدينا خطط غير محددة لـ Turbopack بعد ذلك، لكننا نرغب في تقييد هذا المنشور بما يمكننا شحنه بثقة في المستقبل المنظور. قد نتحدث عن ميزتين فقط، ولكن هناك الكثير مما يدخل فيهما، لذا من الجدير التعمق فيهما.

التخزين المؤقت الدائم (تحديث سريع عبر عمليات إعادة التشغيل)

يعني التخزين المؤقت الدائم تخزين العمل الذي قام به المترجم بطريقة تسمح بإعادة استخدامه عبر عمليات إعادة تشغيل خادم التطوير أو عبر عمليات بناء متعددة للإنتاج.

باختصار، يتجنب Turbopack إعادة نفس العمل، حتى إذا قمت بإعادة التشغيل.

كما ذكرنا في قسم "تحديث أسرع (Faster Fast Refresh)"، قمنا ببناء Turbo Engine لضمان إمكانية تقسيم العمل إلى أجزاء متوازية وتخزينه مؤقتًا، بحيث عندما تقوم بتغيير ملف، يتعين علينا فقط تشغيل العمل المتعلق بهذا التغيير. ماذا لو استطعنا أن نقدم لك هذه التجربة عبر عمليات إعادة التشغيل وعند فتح مسار؟ لن نضطر إلى إعادة عمل التجميع الذي تم بالفعل في جلسة تطوير سابقة. ماذا لو استطعنا الحصول على فوائد التحديث السريع ولكن لفتح المسارات المترجمة في جلسات تطوير سابقة وعبر عمليات بناء متعددة باستخدام next build؟

هذا بالضبط ما كنا نعمل عليه: طبقة تخزين جديدة لـ Turbo Engine تدعم استمرار عمل التجميع على القرص واستعادته عند بدء خادم التطوير أو البناء مرة أخرى.

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

على عكس التخزين المؤقت على القرص الموجود مع webpack، فإن التخزين المؤقت الدائم مع Turbopack يشعر حقًا مثل التحديث السريع عبر عمليات إعادة التشغيل. المسارات التي تستغرق أكثر من 10 ثوانٍ للتجميع في المرة الأولى تستغرق أقل من 500 مللي ثانية للاستعادة من التخزين المؤقت بمجرد تجميعها مرة واحدة.

لقد رأينا نتائج مماثلة لـ next build مع Turbopack، حيث يتم إعادة تجميع الملفات المتغيرة فقط، ويبقى كل شيء آخر كما هو. في الخطوات المتعددة التي يتخذها next build، ينقل هذا معظم الوقت المستغرق من تشغيل التجميع والتعبئة إلى تشغيل التحقق من نوع TypeScript.

التخزين المؤقت الدائم حاليًا قيد العمل، حيث نريد التحقق منه باستخدام تطبيقات Next.js الداخلية أولاً. النتائج الأولية واعدة جدًا، وسيتحسن الأداء أكثر بمرور الوقت بينما نواصل تحسين هذه المسارات الساخنة.

بمجرد استقرار التخزين المؤقت الدائم، سيتم تمكينه افتراضيًا. لن يتطلب تمكين التخزين المؤقت الدائم إجراء تغييرات على قاعدة التعليمات البرمجية الخاصة بك.

إذا كنت مهتمًا باختبار التخزين المؤقت الدائم، يرجى التواصل!

عمليات البناء للإنتاج

نحن متحمسون لمشاركة أننا نحقق تقدمًا كبيرًا نحو عمليات بناء مستقرة للإنتاج باستخدام Turbopack. حاليًا، 96% من اختبارات الإنتاج لدينا تمر، وهي خطوة كبيرة إلى الأمام. ومع ذلك، لا تزال هناك مجالات تحتاج إلى مزيد من العمل قبل أن نتمكن من التوصية بثقة بـ Turbopack للإنتاج على نطاق واسع.

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

تحسينات الإنتاج

الدقة

ضمان الدقة أمر ضروري لعمليات بناء إنتاج موثوقة. إليك الحالة الحالية:

  • تجزئة CSS: قيد التقدم. هذه الميزة ضرورية لتقسيم CSS إلى أجزاء أصغر، مما يسمح بتحميل CSS الضروري فقط لكل جزء من التطبيق، مما يساعد في تقليل أوقات التحميل ويضمن الترتيب الصحيح لقواعد CSS.
  • وقت تشغيل JavaScript للإنتاج: مكتمل. هذا يضمن أن وقت تشغيل JavaScript يعمل كما هو متوقع في بيئة إنتاج، مما يوفر الموثوقية والاستقرار.
  • تجزئة أسماء الملفات بناءً على المحتوى: لم يتم تنفيذها بعد. التجزئة بناءً على المحتوى ستسمح لنا بإنشاء أسماء ملفات بناءً على المحتوى، مما يمكّن من تخزين مؤقت أكثر كفاءة في المتصفحات على المدى الطويل.

تحسينات أداء تجربة المستخدم (UX Performance Optimizations)

أداء تجربة المستخدم هو عنصر أساسي لتحقيق أوقات تحميل سريعة واستخدام فعال للموارد. إليكم ما نعمل عليه:

  • تصغير ملفات JS (JS Minify): مكتمل. قمنا بتنفيذ تصغير SWC الذي يستخدمه Next.js بالفعل مع webpack منذ Next.js 13.
  • تصغير ملفات CSS (CSS Minify): مكتمل. تصغير CSS باستخدام Lightning CSS، وهو أمر مهم لتقليل حجم ملفات الأنماط.
  • المعلومات الشاملة (تحسينات التطبيق بالكامل - Whole Application Optimizations): مكتمل. يمكن لـ Turbopack تطبيق تحسينات تتطلب بيانات عن جميع المسارات في التطبيق، مثل تجزئة معرفات الوحدات (module id hashing).
  • هز الشجرة (Tree Shaking): مكتمل جزئيًا. قيد التقدم. لدينا دعم جزئي لهز الشجرة، مما يساعد في إزالة الأكواد غير المستخدمة وتقليل أحجام الحزم. ومع ذلك، هناك سيناريوهات لم يصبح هز الشجرة فعالًا بالكامل فيها بعد:
    • الاستيراد الديناميكي (Dynamic Imports): هز الشجرة محدود للاستيرادات الديناميكية مثل استخدام next/dynamic.
    • التصديرات المعقدة (Complex Exports): أنواع معينة من التصديرات مثل export { foo as "string name" }.
    • وحدات غير ES (Non-ES Modules): وحدات CommonJS لا يمكن هز شجرتها.
    • ملفات البرميل (Barrel Files): إعادة التصدير من ملفات البرميل غير فعالة، مع قيود في تخطي الوحدات الخالية من الآثار الجانبية.
    • التجزئة (Fragmentation): في بعض الحالات، يمكن أن يؤدي هز الشجرة إلى إنشاء الكثير من الأجزاء، مما يؤدي إلى حزم غير فعالة.
  • تجزئة معرف الوحدة (Module ID Hashing - Partial): قيد التقدم. تم تنفيذ تجزئة معرف الوحدة جزئيًا ولكننا نعمل على تحسين الأداء. بمجرد تمكينها بالكامل، ستساعد في تقليل حجم الحزمة النهائية.
  • تشويش أسماء التصدير (Export Name Mangling): قيد التقدم. يتضمن ذلك تقليل حجم أسماء التصدير لتقليل حجم الحزمة النهائية.
  • رفع النطاق (Scope Hoisting): لم يتم تنفيذه بعد. سيساعد رفع النطاق في تقليل حجم الحزمة عن طريق دمج وحدات JavaScript الأصغر في نطاق واحد، مما يقلل من الحمل الزائد ويحسن الأداء.
  • تجزئة JS محسنة للإنتاج (Production Optimized JS Chunking): لم يتم تنفيذه بعد. تعد تجزئة JavaScript لتقليل التكرار أمرًا ضروريًا لتحسين أداء التحميل، خاصة للتطبيقات الكبيرة.

ترقبوا المزيد (Stay Tuned)

يسعدنا أن نوصي بثقة باستخدام next dev --turbo، ولا يمكننا الانتظار لسماع كيف يحسن تجربة التطوير لديكم. جربوه اليوم وشاهدوا تحسن الأداء بأنفسكم.

هذه مجرد البداية - التخزين المؤقت الدائم وحزم الإنتاج في الطريق، مما سيجلب المزيد من السرعة والموثوقية لسير عملكم.

سنشارك المزيد من التحديثات مع تقدمنا نحو ضمان الصحة وتحسين الأداء للتعامل مع أكبر التطبيقات بسلاسة. ترقبوا الإصدارات والتحسينات المستقبلية بينما نعمل على جعل Turbopack الحل الأفضل لكل من حزم التطوير والإنتاج.

المساهمون (Contributors)

نشكر آلاف المطورين الذين شاركوا في الاختبار وإبلاغ المشكلات والتحقق من الإصلاحات خلال مراحل بيتا ومرشح الإصدار لـ Turbopack.

هذا الإصدار مقدم لكم بواسطة: