تجميع جافا سكريبت والأداء: أفضل الممارسات

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



يستكشف مؤلف المقال ، الذي ننشره اليوم ، ثلاثة طرق لتجميع مشاريع JavaScript باستخدام مثال تطبيق Hello World البسيط الذي تم إنشاؤه باستخدام React. تتضمن بعض الأمثلة التي يستشهد بها قراءة أساسيات منشئي الوحدات النمطية ، مثل Webpack ، والتي يبدو أنها الأداة الأكثر شعبية اليوم.

المنهج رقم 1: كل شيء يدخل في الحزم (يبدو ككرة كبيرة من الخيط)


الفكرة الرئيسية: لا تستخدم هذا النهج.

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

 <!-- index.html --> <script src="bundle.[hash].min.js"></script> 

قبل إصدار HTTP / 2 ، يمكن اعتبار هذا النمط ، بطريقة ما ، مقبولًا تمامًا ، حيث أن استخدامه يقلل من عدد طلبات HTTP التي ينفذها المستعرض عند تحميل مواد الصفحة. ولكن بالنظر إلى أن معظم المواقع اليوم تستخدم HTTP / 2 ، فقد أصبح هذا النمط مضادًا للانزلاق.

لماذا؟ الحقيقة هي أنه عند استخدام HTTP / 2 ، فإن تنفيذ العديد من الطلبات لم يعد ينشئ نفس الحمل على النظام كما كان من قبل. نتيجة لذلك ، فإن تعبئة الكود في حزمة واحدة كبيرة لم تعد تمنح المشروع مزايا كبيرة.

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

يدعم HTTP / 2 اليوم أكثر من 95٪ من العملاء . في عام 2019 ، تم تنفيذ هذا البروتوكول من قبل معظم الخوادم. تعرف على المزيد حول استخدام HTTP / 2 في 2019 هنا.

المنهج رقم 2: عبوة منفصلة لرمز المشروع ورمز مكتبات الطرف الثالث (فصل الكود)


الفكرة الرئيسية: يرجى استخدام هذا النهج.

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

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

إليك ما أصبح رمز اتصال البرنامج النصي:

 <!-- index.html --> <script src="vendor.[hash].min.js"></script> <script src="index.[hash].min.js"></script> 

وهنا الجدول الزمني للشلال لتحميل الصفحة ، عند العمل باستخدام HTTP / 2.


جدول تحميل صفحة الشلال

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

 <!-- index.html --> <script src="vendor.react.[hash].min.js"></script> <script src="vendor.others.[hash].min.js"></script> <script src="index.[hash].min.js"></script> 

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

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

المنهج رقم 3: استخدام شبكات CDN العامة لرمز بعض التبعيات


الفكرة الرئيسية: لا تستخدم هذا النهج.

إذا كنت أحد هؤلاء الأشخاص الذين عتيقوا في تطوير الويب (مثلي) ، فقد يكون لديك شعور داخلي بأننا قد نتمكن من توصيل ملف vendor.react ، الذي تمت مناقشته في القسم "النهج رقم". 2 "، باستخدام مورد CDN عام:

 <!-- index.html --> <script crossorigin src="https://unpkg.com/react@16.12.0/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.production.min.js"></script> <script src="index.[hash].min.js"></script> 

ألاحظ أنه عند استخدام هذا النهج ، من الضروري إخبار جامع مشروع Webpack بأنه يجب أن يستبعد كود react-dom من الحزمة.

للوهلة الأولى ، يبدو كل هذا جيدًا ، لكن هذا النهج له بعض العيوب التي أقترح دراستها.

▍ ناقص # 1: استخدام مواقع مختلفة من نفس ملفات التبعية؟ لم يعد ...


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

على الرغم من أن هذا قد يكون ناجحًا في وقت مبكر ، مؤخرًا في المتصفحات ، من أجل زيادة الأمان ، إلا أنهم بدأوا في تطبيق آلية مشاركة ذاكرة التخزين المؤقت. نحن نتحدث عن حقيقة أنه حتى في ظل الظروف المثالية ، عندما يستخدم موقعان نفس المكتبة ، ويتم تحميلهما عبر ارتباط CDN نفسه ، يتم تنزيل الكود بشكل مستقل لكل مجال ، وينتهي التخزين المؤقت لأسباب تتعلق بالخصوصية في صندوق الحماية المخصصة لمجال معين. كما اتضح ، تم تنفيذ هذه الآلية بالفعل في Safari (على ما يبدو ، إنها موجودة منذ عام 2013؟!). وإذا تحدثنا عن Chrome 77 ، فعندئذٍ لتمكين فصل ذاكرة التخزين المؤقت في الوقت الحالي ، فأنت بحاجة إلى استخدام علامة خاصة.

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

▍ ناقص رقم 2: إهدار موارد النظام على العمليات المساعدة (لكل مجال)


يتم التعبير عن الفكرة هنا أن استخدام CDN يؤدي إلى زيادة الحمل على النظام ، لأنه قبل إرسال طلب HTTP ، يحتاج المستعرض إلى حل العديد من المشكلات: تحليل اسم DNS ، اتصال TCP ، مصافحة طبقة المقابس الآمنة. للاتصال بالموقع ، يتعين على المستعرض تنفيذ هذه الإجراءات في أي حال ، ولكن إذا كان مضطرًا للاتصال بـ CDN أيضًا ، فهذا يزيد من التحميل عليه.

فيما يلي رسم بياني لشلال يوضح عملية تحميل صفحة تستخدم برامج نصية من مورد CDN متاح للجمهور.


الجدول الزمني للشلال لتحميل صفحة باستخدام موارد CDN المتاحة للجمهور

تبرز الأشكال البيضاوية الحمراء المناطق التي تحدث فيها عمليات تسبق تنفيذ الاستعلامات. هذا يبدو أكثر من اللازم لتطبيق Hello World البسيط.

مع تطور مثالي البسيط وتنموه ، سيأتي وقت أرغب في استخدام خطي فيه. على سبيل المثال - مأخوذة من Google Fonts. وهذا يعني أن عدد هذه التأخيرات سيزداد فقط ، حيث سيتعين عليك الاتصال بالمجال المقابل لتنزيل الخطوط. هنا تبدو فكرة استضافة جميع موارد الموقع على نطاقه الرئيسي (والذي يقع بالطبع وراء مورد CDN الخاص بالمشروع استنادًا إلى Cloudflare أو Cloudfront) جذابة للغاية.

إذا تحولنا في مثالنا إلى تنزيل اثنين من التبعيات React من المجال الرئيسي للموقع ، فسيؤدي ذلك إلى حقيقة أن جدول الشلال لتحميل الصفحة سوف يصبح أكثر دقة.


جدول تحميل الشلال لصفحة لا تستخدم موارد CDN المتاحة للجمهور

رقم 3: استخدام إصدارات مختلفة من التبعيات من قبل مواقع مختلفة


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


تتفاعل الإصدارات المستخدمة من قبل مواقع مختلفة

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

خلال البحث ، وجدت بعض المعلومات الأكثر إثارة للاهتمام حول مواقع React هذه. ربما سيبدو الأمر مثيرًا لك أيضًا:

  • في 2/3 مواقع ، يتم استخدام Webpack لإنشاء رمز.
  • يستخدم 87٪ من المواقع HTTP / 2 ، وهو أكثر من متوسط ​​القيمة البالغ 58٪.
  • تستضيف معظم المشروعات (حوالي 56٪) الخطوط نفسها.

فيما يلي البيانات المصدر لتجربتي.

inMinus رقم 4: قضايا عدم الأداء


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

  • قضايا الأمن. هناك مشكلات أمنية مرتبطة باستخدام موارد CDN المتاحة للجمهور بخلاف تلك التي تهدف إلى حل مشاركة ذاكرة التخزين المؤقت في المتصفحات. على سبيل المثال ، إذا قام المتسللون باقتحام مورد CDN يمكن الوصول إليه بشكل عام ، فيمكنهم حقًا ضخ تعليمات برمجية JavaScript ضارة في المكتبات. ستحصل هذه الشفرة على جميع امتيازات رمز الموقع التي يتم تنفيذها على العميل ، وستكون قادرة على التعامل مع بيانات المستخدمين الذين قاموا بتسجيل الدخول إلى الموقع.
  • قضايا الخصوصية. تقوم العديد من الشركات بجمع بيانات المستخدم من الطلبات المقدمة من موارد الجهة الخارجية. من الناحية النظرية ، إذا تم استخدام مورد CDN المتاح للعموم لتنزيل رمز أو خطوط التبعية على جميع المواقع ، فسيكون مورد CDN هذا قادرًا على تتبع جلسات عمل المستخدم وميزات عملهم على الإنترنت. سيتمكن مورد مماثل من تكوين افتراضات حول ما يهمهم (على سبيل المثال ، لأغراض الدعاية). وكل هذا - دون استخدام ملفات تعريف الارتباط!
  • نقطة واحدة من الفشل. يؤدي توزيع المواد اللازمة لتشغيل الموقع عبر مجالات متعددة إلى زيادة فرصه ، نظرًا لوجود مشكلات في أحد هذه المجالات ، سيتمكن العميل من تنزيل جزء فقط من المواد اللازمة لجعل الصفحات في حالة صالحة للعمل. لكي نكون صادقين ، يمكن حل هذه المشكلات باستخدام جافا سكريبت ، ولكن على مطور الموقع أن يبذل بعض الجهود الإضافية.

النتائج


من الواضح أن المستقبل يكمن في النهج رقم 2.

استضافة موارد CDN الخاصة بك أمام الخوادم الخاصة بك باستخدام HTTP / 2 (مثل Cloudflare أو Cloudfront). قسم الكود إلى أجزاء صغيرة من أجل استخدام ذاكرة التخزين المؤقت للمتصفح بشكل فعال. في المستقبل ، قد تصبح الشظايا التي ينقسم إليها رمز الموقع أصغر ، بحيث تصل إلى حجم وحدات جافا سكريبت الفردية ، نظرًا لأن المتصفحات بدأت في تطبيق الدعم لهذه التكنولوجيا.

أعزائي القراء! هل تستخدم تقنيات فصل الكود في مشاريع الويب الخاصة بك؟

Source: https://habr.com/ru/post/ar483682/


All Articles