00:00:00(موسيقى حماسية) - حسنًا، شكرًا لكم جميعًا، مرحبًا.
00:00:07اسمي لوك ساندبرغ.
00:00:09أنا مهندس برمجيات في Vercel، أعمل على Turbo Pack.
00:00:12لقد أمضيت حوالي ستة أشهر في Vercel، وهي مدة كافية لأصعد إلى هنا على المسرح وأخبركم عن كل العمل الرائع الذي لم أقم به.
00:00:23قبل عملي في Vercel، كنت في Google، حيث عملت على سلاسل أدوات الويب الداخلية لدينا وقمت بأشياء غريبة مثل بناء مترجم TSX إلى Java byte code والعمل على مترجم Closure.
00:00:37لذا عندما وصلت إلى Vercel، كان الأمر أشبه بالهبوط على كوكب آخر، كل شيء كان مختلفًا.
00:00:45وقد تفاجأت حقًا بكل ما قمنا به في الفريق وبالأهداف التي وضعناها.
00:00:50لذا سأشارككم اليوم بعض خيارات التصميم التي اتخذناها في Turbo Pack وكيف أعتقد أنها ستسمح لنا بالاستمرار في البناء على الأداء الرائع الذي نملكه بالفعل.
00:01:01وللمساعدة في توضيح ذلك، هذا هو هدفنا التصميمي العام.
00:01:06من هذا، يمكنكم أن تستنتجوا فورًا أننا على الأرجح اتخذنا بعض الخيارات الصعبة.
00:01:14إذًا، ماذا عن البناء البارد (Cold Builds)؟
00:01:17إنها مهمة، ولكن إحدى أفكارنا هي أنكم لا يجب أن تختبروها على الإطلاق.
00:01:22وهذا ما سيركز عليه هذا الحديث.
00:01:24في الكلمة الافتتاحية، سمعتم قليلاً عن كيف نستفيد من التزايدية لتحسين أداء التجميع.
00:01:31فكرة رئيسية لدينا للتزايدية تتعلق بالتخزين المؤقت (Caching).
00:01:35نريد أن نجعل كل شيء يفعله المجمّع قابلاً للتخزين المؤقت، بحيث كلما أجريت تغييرًا، لا نضطر إلا لإعادة العمل المتعلق بهذا التغيير.
00:01:43أو ربما بعبارة أخرى، يجب أن تتناسب تكلفة البناء الخاص بك حقًا مع حجم أو تعقيد التغيير الذي أجريته، بدلاً من حجم أو تعقيد تطبيقك.
00:01:53وهذه هي الطريقة التي نضمن بها أن Turbo Pack سيستمر في تقديم أداء جيد للمطورين بغض النظر عن عدد مكتبات الأيقونات التي تستوردونها.
00:02:01للمساعدة في فهم هذه الفكرة وتوضيحها، دعونا نتخيل أبسط مجمّع في العالم، والذي قد يبدو هكذا.
00:02:09إذًا، هذا هو مجمّعنا الصغير.
00:02:12وربما هذا كثير جدًا من التعليمات البرمجية لوضعها على شريحة، لكن الأمر سيزداد سوءًا.
00:02:17هنا نقوم بتحليل كل نقطة دخول.
00:02:20نتتبع وارداتها، ونحل مراجعها، بشكل متكرر في جميع أنحاء التطبيق للعثور على كل ما تعتمدون عليه.
00:02:28ثم في النهاية، نجمع ببساطة كل ما تعتمد عليه كل نقطة دخول ونضعه في ملف إخراج.
00:02:35إذًا، يا للروعة، لدينا مجمّع صغير.
00:02:38من الواضح أن هذا ساذج، لكن إذا فكرنا فيه من منظور تزايدي، فلا يوجد جزء منه تزايدي.
00:02:45لذا سنقوم بالتأكيد بتحليل ملفات معينة عدة مرات، ربما اعتمادًا على عدد مرات استيرادها، وهذا أمر فظيع.
00:02:53سنقوم بالتأكيد بحل استيراد React مئات أو آلاف المرات.
00:02:57لذا، كما تعلمون، هذا مؤلم.
00:03:01لذا إذا أردنا أن يكون هذا تزايديًا أكثر قليلاً على الأقل، نحتاج إلى إيجاد طريقة لتجنب العمل الزائد.
00:03:08لذا دعونا نضيف ذاكرة تخزين مؤقتة.
00:03:10قد تتخيلون أن هذه هي دالة التحليل الخاصة بنا.
00:03:15إنها بسيطة جدًا.
00:03:15وربما هي بمثابة جواد العمل لمجمّعنا.
00:03:19كما تعلمون، بسيطة جدًا.
00:03:19نقرأ محتويات الملف، ثم نسلمها إلى SWC لتعطينا شجرة بناء مجردة (AST).
00:03:25لذا دعونا نضيف ذاكرة تخزين مؤقتة.
00:03:27حسنًا، هذا بوضوح فوز بسيط وجميل.
00:03:31لكن، كما تعلمون، أنا متأكد أن بعضكم قد كتب تعليمات برمجية للتخزين المؤقت من قبل.
00:03:36ربما هناك بعض المشاكل هنا.
00:03:38مثل، ماذا لو تغير الملف؟
00:03:41هذا بوضوح شيء نهتم به.
00:03:46وماذا لو لم يكن الملف ملفًا حقيقيًا، بل ثلاثة روابط رمزية في كود معقد؟
00:03:52الكثير من مديري الحزم ينظمون التبعيات بهذه الطريقة.
00:03:55ونحن نستخدم اسم الملف كمفتاح للتخزين المؤقت.
00:03:59هل هذا كافٍ؟
00:04:00مثل، كما تعلمون، نحن نجمع للعميل والخادم.
00:04:03نفس الملفات تنتهي في كليهما.
00:04:04هل هذا يعمل؟
00:04:05نحن أيضًا نخزن شجرة البناء المجردة (AST) ونعيدها.
00:04:08لذا الآن علينا أن نقلق بشأن التعديلات.
00:04:11إذًا، كما تعلمون، وأخيرًا، أليست هذه طريقة ساذجة حقًا للتحليل؟
00:04:16أعلم أن الجميع لديهم إعدادات ضخمة للمترجم.
00:04:21مثل، بعض ذلك يجب أن يدخل هنا.
00:04:23لذا، نعم، هذه كلها ملاحظات رائعة.
00:04:27وهذا نهج ساذج جدًا.
00:04:32وعلى ذلك، بالطبع، أقول، نعم، هذا لن ينجح.
00:04:36إذًا ماذا نفعل لإصلاح هذه المشاكل؟
00:04:39الرجاء الإصلاح وعدم ارتكاب أخطاء.
00:04:44إذًا، حسنًا.
00:04:46ربما هذا أفضل قليلاً.
00:04:49كما ترون هنا، لدينا بعض التحويلات.
00:04:52نحتاج إلى القيام بأشياء مخصصة لكل ملف، مثل ربما خفض المستوى (down-leveling) أو تطبيق استخدام التخزين المؤقت (use cache).
00:04:58لدينا أيضًا بعض الإعدادات.
00:05:00وبالطبع، نحتاج إلى تضمين ذلك في مفتاح ذاكرة التخزين المؤقت الخاصة بنا.
00:05:04لكن ربما تشكون فورًا.
00:05:08مثل، هل هذا صحيح؟
00:05:09مثل، هل يكفي حقًا تحديد تحويل بناءً على الاسم؟
00:05:13لا أعرف، ربما لديه بعض الإعدادات المعقدة الخاصة به.
00:05:16وهل قيمة JSON هذه ستلتقط حقًا كل ما نهتم به؟
00:05:24هل سيقوم المطورون بصيانتها؟
00:05:26ما مدى حجم مفاتيح التخزين المؤقت هذه؟
00:05:29كم عدد نسخ الإعدادات التي سنمتلكها؟
00:05:31لقد رأيت شخصيًا تعليمات برمجية كهذه تمامًا، وأجدها شبه مستحيلة الفهم والتحليل.
00:05:37حسنًا، حاولنا أيضًا إصلاح مشكلة أخرى تتعلق بالإلغاءات (Invalidations).
00:05:43لذا أضفنا واجهة برمجة تطبيقات (API) لاستدعاء دالة (callback) لقراءة الملف.
00:05:46هذا رائع، فإذا تغير الملف، يمكننا ببساطة حذفه من ذاكرة التخزين المؤقت، وبذلك لن نستمر في تقديم محتويات قديمة.
00:05:55حسنًا، لكن هذا ساذج جدًا في الواقع، لأننا، بالتأكيد، نحتاج إلى حذف ذاكرة التخزين المؤقت الخاصة بنا، لكن المتصل بنا يحتاج أيضًا إلى معرفة أنه يجب عليه الحصول على نسخة جديدة.
00:06:03إذًا، حسنًا، دعونا نبدأ في تمرير دوال الاستدعاء (callbacks).
00:06:06حسنًا، لقد فعلناها.
00:06:09لقد قمنا بتمرير دوال الاستدعاء عبر المكدس (stack).
00:06:12يمكنكم أن تروا هنا أننا نسمح للمتصل بنا بالاشتراك في التغييرات.
00:06:16يمكننا ببساطة إعادة تشغيل الحزمة بأكملها إذا تغير أي شيء، وإذا تغير ملف، فإننا نستدعيها.
00:06:22رائع، لدينا مجمّع تفاعلي.
00:06:25لكن هذا لا يزال بالكاد تزايديًا.
00:06:28لذا إذا تغير ملف، نحتاج إلى المرور على جميع الوحدات مرة أخرى وإنتاج جميع ملفات الإخراج.
00:06:37لذا، كما تعلمون، لقد وفرنا الكثير من العمل بفضل ذاكرة التخزين المؤقت للتحليل الخاصة بنا، لكن هذا ليس كافيًا حقًا.
00:06:45ثم أخيرًا، هناك كل هذا العمل الزائد الآخر.
00:06:49مثل، نريد بالتأكيد تخزين الواردات مؤقتًا.
00:06:52قد نجد ملفًا عدة مرات، ونستمر في الحاجة إلى وارداته، لذا نريد وضع ذاكرة تخزين مؤقتة هناك.
00:06:57وكما تعلمون، نتائج الحل (resolve results) معقدة جدًا في الواقع، لذا يجب علينا بالتأكيد تخزينها مؤقتًا حتى نتمكن من إعادة استخدام العمل الذي قمنا به في حل React.
00:07:08لكن، حسنًا، الآن لدينا مشكلة أخرى.
00:07:11تتغير نتائج الحل الخاصة بكم عندما تقومون بتحديث التبعيات أو إضافة ملفات جديدة، لذا نحتاج إلى دالة استدعاء أخرى هناك.
00:07:18ونريد بالتأكيد أيضًا، مثل، تخزين منطق إنتاج المخرجات مؤقتًا، لأنكم إذا فكرتم في جلسة HMR، فأنتم تعدلون جزءًا واحدًا من التطبيق، فلماذا نعيد كتابة جميع المخرجات في كل مرة؟
00:07:31وأيضًا، قد تقومون، مثل، بحذف ملف إخراج، لذا يجب أن نستمع إلى التغييرات هناك أيضًا.
00:07:39حسنًا، ربما حللنا كل تلك الأمور، لكن لا تزال لدينا هذه المشكلة، وهي أننا في كل مرة يتغير فيها أي شيء، نبدأ من الصفر.
00:07:48لذا، نوعًا ما، تدفق التحكم الكامل لهذه الدالة لا يعمل لأنه إذا تغير ملف واحد، فإننا نود حقًا القفز إلى منتصف حلقة التكرار تلك.
00:07:56ثم، أخيرًا، واجهة برمجة التطبيقات (API) الخاصة بنا للمتصل بنا ساذجة بشكل ميؤوس منه أيضًا.
00:08:03ربما يريدون في الواقع معرفة أي ملف قد تغير، حتى يتمكنوا، مثل، من دفع التحديثات إلى العميل.
00:08:07لذا، نعم.
00:08:11لذا، هذا النهج لا يعمل حقًا.
00:08:13وحتى لو قمنا بطريقة ما بتمرير جميع دوال الاستدعاء في جميع هذه الأماكن، هل تعتقدون أنكم تستطيعون بالفعل صيانة هذا الكود؟
00:08:21هل تعتقدون أنكم تستطيعون، مثل، إضافة ميزة جديدة إليه؟
00:08:24لا أعتقد ذلك.
00:08:25أعتقد أن هذا سينهار ويحترق.
00:08:28وكما تعلمون، على ذلك، أقول، نعم.
00:08:34إذًا، مرة أخرى، ماذا يجب أن نفعل؟
00:08:36كما تعلمون، تمامًا كما تتحدثون مع نموذج لغوي كبير (LLM)، تحتاجون أولاً إلى معرفة ما تريدونه.
00:08:43ثم يجب أن تكونوا واضحين للغاية بشأنه.
00:08:48إذًا، ماذا نريد حتى؟
00:08:50لذا، كما تعلمون، لقد درسنا الكثير من الأساليب المختلفة، والعديد من الأشخاص في الفريق كان لديهم بالفعل الكثير من الخبرة في العمل على المجمّعات.
00:08:59لذا، توصلنا إلى هذه المتطلبات التقريبية.
00:09:02لذا، نريد بالتأكيد أن نكون قادرين على تخزين كل عملية مكلفة في المجمّع مؤقتًا.
00:09:05ويجب أن يكون القيام بذلك سهلاً حقًا.
00:09:08مثل، لا يجب أن تحصلوا على 15 تعليقًا على مراجعة الكود الخاص بكم في كل مرة تضيفون فيها ذاكرة تخزين مؤقتة جديدة.
00:09:12ثم أنا لا أثق حقًا بالمطورين لكتابة مفاتيح تخزين مؤقت صحيحة أو تتبع المدخلات أو تتبع التبعيات يدويًا.
00:09:24لذا، يجب علينا التعامل معها.
00:09:26يجب علينا بالتأكيد جعل هذا مضمونًا.
00:09:30بعد ذلك، نحتاج إلى التعامل مع المدخلات المتغيرة.
00:09:33هذه فكرة كبيرة في HMR، ولكن حتى عبر الجلسات.
00:09:36لذا، في الغالب ستكون هذه ملفات، لكن يمكن أن تكون أيضًا أشياء مثل إعدادات التكوين.
00:09:40ومع ذاكرة التخزين المؤقت لنظام الملفات، ينتهي الأمر بأن تكون أشياء مثل متغيرات البيئة أيضًا.
00:09:45لذا، نريد أن نكون تفاعليين.
00:09:47نريد أن نكون قادرين على إعادة حساب الأشياء بمجرد تغير أي شيء، ولا نريد تمرير دوال الاستدعاء في كل مكان.
00:09:54أخيرًا، نحتاج فقط إلى الاستفادة من البنى الحديثة وأن نكون متعددين الخيوط (multi-threaded) وسريعين بشكل عام.
00:10:02لذا، ربما تنظرون إلى هذه المجموعة من المتطلبات، وبعضكم يفكر، ما علاقة هذا بالمجمّع؟
00:10:12وعلى ذلك، أقول، بالطبع، فريق الإدارة الخاص بي موجود في الغرفة، لذا لا نحتاج حقًا للحديث عن ذلك.
00:10:20لكن في الحقيقة، أعتقد أن الكثير منكم قفز إلى الاستنتاج الأكثر وضوحًا بكثير.
00:10:24هذا يبدو كثيرًا مثل الإشارات (signals).
00:10:28ونعم، أنا أصف نظامًا يبدو مثل الإشارات.
00:10:31إنها طريقة لتكوين العمليات الحسابية، وتتبع التبعيات، مع قدر معين من التخزين المؤقت التلقائي (automatic memoization).
00:10:37ويجب أن أشير إلى أننا استلهمنا من جميع أنواع الأنظمة، وخاصة مترجم Rust ونظام يسمى Salsa.
00:10:45وهناك حتى أدبيات أكاديمية حول هذه المفاهيم تسمى Adaptons، إذا كنتم مهتمين.
00:10:51حسنًا، دعونا نلقي نظرة على ما يبدو عليه هذا عمليًا، ثم سنقوم بقفزة مفاجئة جدًا من أمثلة الكود في JavaScript إلى Rust.
00:11:01إذًا، هذا مثال على البنية التحتية التي بنيناها.
00:11:05دالة TurboTask هي وحدة عمل مخزنة مؤقتًا في مترجمنا.
00:11:12لذا يمكننا، بمجرد إضافة تعليق توضيحي لدالة كهذه، تتبعها، وبناء مفتاح تخزين مؤقت من معاملاتها، وهذا يسمح لنا بتخزينها مؤقتًا وإعادة تنفيذها عند الحاجة.
00:11:28هذه الأنواع من VC هنا، يمكنكم التفكير فيها كإشارات، هذه قيمة تفاعلية، VC تعني خلية قيمة (value cell)، لكن إشارة (signal) قد يكون اسمًا أفضل قليلاً.
00:11:39عندما تعلنون عن معامل كهذا، فأنتم تقولون إن هذا قد يتغير، أريد إعادة التنفيذ عندما يتغير.
00:11:47وكيف نعرف ذلك؟
00:11:49لذا نقرأ هذه القيم عبر عملية انتظار.
00:11:52بمجرد أن تنتظروا قيمة تفاعلية كهذه، فإننا نتتبع التبعية تلقائيًا.
00:11:58ثم أخيرًا، بالطبع، نقوم بالعملية الحسابية الفعلية التي أردنا القيام بها، ونخزنها في خلية.
00:12:07لذا بما أننا تتبعنا التبعيات تلقائيًا، فإننا نعلم أن هذه الدالة تعتمد على كل من محتويات الملف وقيمة الإعدادات.
00:12:17وفي كل مرة نخزن نتيجة جديدة في الخلية، يمكننا مقارنتها بالنتيجة السابقة، ثم إذا تغيرت، يمكننا نشر الإشعارات إلى كل من قرأ تلك القيمة.
00:12:29لذا فإن مفهوم التغيير هذا هو مفتاح نهجنا في التزايدية.
00:12:33ونعم، مرة أخرى، أبسط حالة هي هنا.
00:12:37إذا تغير الملف، سيلاحظ Turbo Pack ذلك، ويلغي تنفيذ هذه الدالة، ويعيد تنفيذها فورًا.
00:12:45ثم إذا حدث أن أنتجنا نفس شجرة البناء المجردة (AST)، فسنتوقف عند هذا الحد لأننا نحسب نفس الخلية.
00:12:53الآن، بالنسبة لتحليل ملف، لا يوجد تقريبًا أي تعديل يمكنكم إجراؤه عليه لا يغير شجرة البناء المجردة (AST) بالفعل.
00:13:00لكن يمكننا الاستفادة من قابلية التركيب الأساسية لدوال Turbo Pack للمضي قدمًا في هذا.
00:13:07لذا هنا، نرى دالة تخزين مؤقت أخرى لـ Turbo Pack تستخرج الواردات من وحدة نمطية.
00:13:15يمكنكم أن تتخيلوا أن هذه مهمة شائعة جدًا لدينا في المجمّع.
00:13:20نحتاج إلى استخراج الواردات فقط للعثور على جميع الوحدات النمطية في تطبيقكم.
00:13:25نستفيد منها لاختيار أفضل طريقة لتجميع الوحدات النمطية معًا في أجزاء (chunks).
00:13:29وبالطبع، رسم بياني الواردات مهم للمهام الأساسية مثل إزالة الشجر (tree shaking).
00:13:34ولأن هناك العديد من المستهلكين المختلفين لبيانات الواردات، فإن ذاكرة التخزين المؤقت منطقية جدًا.
00:13:41لذا هذا التنفيذ ليس مميزًا حقًا.
00:13:44هذا يشبه ما ستجدونه في أي نوع من المجمّعات.
00:13:46نتجول في شجرة البناء المجردة (AST)، ونجمع الواردات في بنية بيانات خاصة نفضلها، ثم نعيدها.
00:13:55لكن الفكرة الرئيسية هنا هي أننا نخزنها في خلية أخرى.
00:13:58لذا إذا تغيرت الوحدة النمطية، نحتاج بالفعل إلى إعادة تشغيل هذه الدالة لأننا قرأناها.
00:14:05لكن إذا فكرتم في نوع التغييرات التي تجرونها على الوحدات النمطية، فإن عددًا قليلاً جدًا منها يؤثر بالفعل على الواردات.
00:14:12لذا تقومون بتغيير الوحدة النمطية، وتحديث جسم الدالة، أو حرف نصي (string literal)، أو أي نوع من تفاصيل التنفيذ.
00:14:20سيؤدي ذلك إلى إلغاء صلاحية هذه الدالة ثم سنحسب نفس مجموعة الواردات.
00:14:25ثم لا نلغي صلاحية أي شيء قرأ هذا.
00:14:29لذا إذا فكرتم في هذا في جلسة HMR، فهذا يعني أننا نحتاج بالفعل إلى إعادة تحليل ملفكم، لكننا لا نحتاج حقًا إلى التفكير في كيفية اتخاذ قرارات التجزئة (chunking) بعد الآن.
00:14:40لا نحتاج إلى التفكير في أي نوع من نتائج إزالة الشجر (tree shaking) لأننا نعلم أنها لم تتغير.
00:14:45لذا يمكننا الانتقال فورًا من تحليل الملف، وإجراء هذا التحليل البسيط، ثم الانتقال مباشرة إلى إنتاج المخرجات.
00:14:53وهذه إحدى الطرق التي نحقق بها أوقات تحديث سريعة جدًا.
00:14:57لذا هذا حتمي جدًا.
00:15:02طريقة أخرى للتفكير في هذه الفكرة الأساسية هي كـ رسم بياني للعقد.
00:15:06لذا هنا على اليسار، قد تتخيلون بناءً باردًا (cold build).
00:15:12في البداية، علينا بالفعل قراءة كل ملف، وتحليلها جميعًا، وتحليل جميع الواردات.
00:15:17وكنتيجة جانبية لذلك، قمنا بجمع جميع معلومات التبعية من تطبيقكم.
00:15:21ثم عندما يتغير شيء ما، يمكننا الاستفادة من رسم بياني التبعية الذي بنيناه لنشر الإلغاءات، عودةً عبر المكدس، وإعادة تنفيذ دوال Turbo Pack.
00:15:32وإذا أنتجوا قيمة جديدة، نتوقف هناك.
00:15:35وإلا، نستمر في نشر الإلغاء.
00:15:37رائع.
00:15:41كما تعلمون، هذا في الواقع نوع من التبسيط المفرط لما نقوم به عمليًا، قد تتخيلون.
00:15:47لذا في Turbo Pack اليوم، هناك حوالي 2500 دالة Turbo task مختلفة.
00:15:53وفي بناء نموذجي، قد يكون لدينا حرفيًا ملايين المهام المختلفة.
00:15:58لذا يبدو الأمر حقًا ربما أكثر قليلاً هكذا.
00:16:01الآن، لا أتوقع حقًا أن تكونوا قادرين على قراءة هذا.
00:16:04لم أستطع حقًا وضعها على الشريحة.
00:16:06لذا ربما يجب أن نصغر الصورة.
00:16:08حسنًا، هذا ليس مفيدًا بشكل واضح.
00:16:14في الواقع، لدينا طرق أفضل نوعًا ما لتتبع وتصور ما يحدث داخل Turbo Pack.
00:16:21لكن بشكل أساسي، تعمل تلك الطرق عن طريق التخلص من الغالبية العظمى من معلومات التبعية.
00:16:26والآن أخمن أن بعضكم ربما لديه بالفعل خبرة في العمل مع الإشارات (signals)، ربما تجارب سيئة.
00:16:34كما تعلمون، أنا شخصيًا أحب تتبعات المكدس (stack traces) والقدرة على الدخول والخروج من الدوال في مصحح الأخطاء (debugger).
00:16:41لذا ربما تشكون في أن هذا هو الحل الشافي الكامل.
00:16:45مثل، من الواضح أنه يأتي مع مقايضات.
00:16:47ونعم، لذا وعلى ذلك أقول بالطبع، حسنًا، كما تعلمون، ما أود قوله حقًا هو أن هندسة البرمجيات كلها تدور حول إدارة المقايضات.
00:17:01نحن لا نحل المشاكل دائمًا بدقة، لكننا نختار مجموعات جديدة من المقايضات لتقديم القيمة.
00:17:08لذا لتحقيق أهدافنا التصميمية حول البناءات التزايدية في Turbo Pack، لقد راهنا بكل ما لدينا على هذا النموذج البرمجي التفاعلي التزايدي.
00:17:19وهذا بالطبع كان له بعض العواقب الطبيعية جدًا.
00:17:23لذا، كما تعلمون، ربما حللنا بالفعل مشكلة أنظمة التخزين المؤقت اليدوية ومنطق الإلغاء المرهق.
00:17:33في المقابل، علينا إدارة بعض البنية التحتية المعقدة للتخزين المؤقت.
00:17:39وبالطبع، كما تعلمون، هذا يبدو لي مقايضة جيدة حقًا.
00:17:42أنا أحب البنية التحتية المعقدة للتخزين المؤقت، لكن علينا جميعًا أن نتعايش مع العواقب.
00:17:48لذا الأول بالطبع هو التكاليف العامة الأساسية لهذا النظام.
00:17:54كما تعلمون، إذا فكرتم في الأمر في بناء معين أو جلسة HMR، فأنتم لا تغيرون الكثير حقًا.
00:18:04لذا نتتبع جميع معلومات التبعية بين كل وارد وكل نتائج حل في تطبيقكم، لكنكم ستغيرون عددًا قليلاً منها فقط.
00:18:13لذا فإن معظم معلومات التبعية التي نجمعها لا تكون مطلوبة بالفعل أبدًا.
00:18:16لذا، كما تعلمون، لإدارة هذا، كان علينا التركيز كثيرًا على دفع، على تحسين أداء طبقة التخزين المؤقت هذه لخفض التكاليف العامة والسماح لنظامنا بالتوسع إلى تطبيقات أكبر وأكبر.
00:18:30والتالي والأكثر وضوحًا هو ببساطة الذاكرة.
00:18:34كما تعلمون، ذاكرات التخزين المؤقت هي دائمًا بشكل أساسي مقايضة بين الوقت والذاكرة.
00:18:38ونظامنا لا يفعل شيئًا مختلفًا حقًا هناك.
00:18:41هدفنا البسيط هو أن حجم ذاكرة التخزين المؤقت يجب أن يتناسب خطيًا مع حجم تطبيقكم.
00:18:49لكن مرة أخرى، علينا أن نكون حذرين بشأن التكاليف العامة.
00:18:51هذا التالي دقيق بعض الشيء.
00:18:54لذا لدينا الكثير من الخوارزميات في المجمّع كما قد تتوقعون.
00:18:58وبعضها يتطلب نوعًا ما فهم شيء عالمي حول تطبيقكم.
00:19:03حسنًا، هذه مشكلة لأنه في أي وقت تعتمدون فيه على معلومات عالمية، فهذا يعني أن أي تغيير قد يلغي صلاحية تلك العملية.
00:19:10لذا علينا أن نكون حذرين بشأن كيفية تصميم هذه الخوارزميات، وتكوين الأشياء بعناية حتى نتمكن من الحفاظ على التزايدية.
00:19:17وأخيرًا، هذه ربما شكوى شخصية بعض الشيء.
00:19:24كل شيء غير متزامن (async) في Turbo Pack.
00:19:27وهذا رائع لقابلية التوسع الأفقي، لكن مرة أخرى، إنه يضر بأهدافنا الأساسية، مثل، كما تعلمون، أهداف تصحيح الأخطاء وتحليل الأداء.
00:19:38لذا أنا متأكد أن الكثير منكم لديه خبرة في تصحيح الأخطاء غير المتزامنة (async) في أدوات مطوري Chrome.
00:19:46وهذه عمومًا تجربة لطيفة جدًا.
00:19:48ليست مثالية دائمًا.
00:19:49وأؤكد لكم أن Rust مع LLDB متأخرة بسنوات ضوئية.
00:19:53لذا لإدارة ذلك، كان علينا الاستثمار في أدوات تصور مخصصة، وأدوات قياس (instrumentation)، وأدوات تتبع.
00:20:01وانظروا إلى ذلك، مثل مشروع بنية تحتية آخر ليس مجمّعًا.
00:20:07حسنًا، دعونا نلقي نظرة ونرى ما إذا كنا قد راهنا بشكل صحيح.
00:20:11لذا في Vercel، لدينا تطبيق إنتاجي كبير جدًا.
00:20:17نعتقد أنه ربما أحد أكبر التطبيقات في العالم، لكن كما تعلمون، لا نعرف حقًا.
00:20:21لكنه يحتوي على حوالي 80,000 وحدة نمطية.
00:20:23لذا دعونا نلقي نظرة على أداء Turbo Pack عليه.
00:20:26بالنسبة للتحديث السريع، نحن نسيطر حقًا على ما يمكن لـ Web Pack تقديمه.
00:20:32لكن هذا نوع من الأخبار القديمة.
00:20:33لقد صدر Turbo Pack للتطوير منذ فترة، وآمل حقًا أن يستخدمه الجميع على الأقل في مرحلة التطوير.
00:20:39لكن كما تعلمون، الشيء الجديد هنا اليوم، بالطبع، هو أن البناءات مستقرة.
00:20:42لذا دعونا نلقي نظرة على بناء.
00:20:44وهنا يمكنكم رؤية فوز كبير على Web Pack لهذا التطبيق.
00:20:49هذا البناء بالذات يعمل في الواقع مع طبقة التخزين المؤقت التجريبية الجديدة لنظام الملفات لدينا.
00:20:53لذا حوالي 16 ثانية من تلك الـ 94 ثانية هي مجرد مسح لذاكرة التخزين المؤقت في النهاية.
00:20:59وهذا شيء سنعمل على تحسينه مع استقرار التخزين المؤقت لنظام الملفات.
00:21:04لكن بالطبع، الأمر المتعلق بالبناءات الباردة هو أنها باردة، لا شيء تزايدي.
00:21:07لذا دعونا نلقي نظرة على بناء دافئ (warm build) فعلي.
00:21:10لذا باستخدام ذاكرة التخزين المؤقت من البناء البارد، يمكننا رؤية هذا.
00:21:14لذا هذه مجرد لمحة عن مكاننا اليوم.
00:21:17لأن لدينا نظام التخزين المؤقت الدقيق هذا، يمكننا بالفعل كتابة ذاكرة التخزين المؤقت على القرص، ثم في البناء التالي، نقرأها مرة أخرى، ونكتشف ما تغير، وننهي البناء.
00:21:26حسنًا، هذا يبدو جيدًا جدًا، لكن الكثير منكم يفكر، حسنًا، ربما أنا شخصيًا لا أمتلك أكبر تطبيق Next.js في العالم.
00:21:34لذا دعونا نلقي نظرة على مثال أصغر.
00:21:37موقع react.dev أصغر بكثير.
00:21:41إنه أيضًا مثير للاهتمام نوعًا ما لأنه مترجم React.
00:21:44ليس من المستغرب أنه من أوائل المتبنين لمترجم React.
00:21:47ومترجم React مطبق في Babel.
00:21:49وهذا نوع من المشاكل لنهجنا لأنه يعني أنه لكل ملف في التطبيق، نحتاج إلى طلب من Babel معالجته.
00:21:55لذا، وبشكل أساسي، أود أن أقول إننا، أو أنا، لا أستطيع جعل مترجم React أسرع.
00:22:01هذه ليست وظيفتي.
00:22:02وظيفتي هي Turbo Pack.
00:22:03لكن يمكننا معرفة متى نستدعيها بالضبط.
00:22:07لذا بالنظر إلى أوقات التحديث السريع، كنت في الواقع محبطًا قليلاً من هذه النتيجة.
00:22:13واتضح أن حوالي 130 من تلك الـ 140 مللي ثانية هي لمترجم React.
00:22:18وكل من Turbo Pack و Web Pack يقومان بذلك.
00:22:22لكن مع Turbo Pack، يمكننا، بعد أن يعالج مترجم React هذا التغيير، أن نرى، أوه، الواردات لم تتغير.
00:22:29ضعها في المخرجات واستمر.
00:22:31مرة أخرى، في البناءات الباردة، نرى هذا النوع من الفوز المتسق بثلاثة أضعاف.
00:22:37وللتوضيح، هذا على جهازي.
00:22:39لكن مرة أخرى، لا توجد تزايدية في البناء البارد.
00:22:44وفي بناء دافئ، نرى هذا الوقت الأفضل بكثير.
00:22:47لذا مرة أخرى، مع بناء دافئ، لدينا بالفعل ذاكرة التخزين المؤقت على القرص.
00:22:52كل ما نحتاج لفعله هو أساسًا، بمجرد أن نبدأ، اكتشاف الملفات التي تغيرت في التطبيق، وإعادة تنفيذ تلك المهام، ثم إعادة استخدام كل شيء آخر من البناء السابق.
00:23:01لذا السؤال الأساسي هو، هل أصبحنا Turbo بعد؟
00:23:05نعم.
00:23:06لذا نعم، نوقش هذا في الكلمة الافتتاحية، بالطبع.
00:23:09Turbo Pack مستقر اعتبارًا من الإصدار التالي 16.
00:23:12ونحن حتى المجمّع الافتراضي لـ Next.
00:23:14لذا، كما تعلمون، المهمة أنجزت، على الرحب والسعة.
00:23:17لكن. (يضحك) (تصفيق الجمهور)
00:23:23وإذا لاحظتم ذلك الشيء المتعلق بالتراجع في الكلمة الافتتاحية، فذلك كنت أنا أحاول جعل Turbo Pack هو الافتراضي.
00:23:30استغرق الأمر ثلاث محاولات فقط.
00:23:31لكن ما أريد حقًا أن أتركه لكم، مرة أخرى، هو هذا.
00:23:35كما تعلمون، لأننا لم ننتهِ بعد.
00:23:37لا يزال لدينا الكثير لنفعله بشأن الأداء، وإنهاء العمل على طبقة التخزين المؤقت لنظام الملفات.
00:23:42أقترح عليكم جميعًا تجربته في مرحلة التطوير.
00:23:44وهذا كل شيء.
00:23:46شكرًا جزيلاً لكم.
00:23:47الرجاء البحث عني، وطرح الأسئلة عليّ.
00:23:49(تصفيق الجمهور) (موسيقى حماسية) (موسيقى حماسية)