اسمي ايليا جولدفارب ، أنا مطور لواجهات ياندكس. أنا مهتم باتباع كيفية تطوير أدوات بناء الواجهة الأمامية ، لذلك أحاول دراسة التغييرات في كل إصدار من الحلول الشائعة.
تحسبا للنسخة الخامسة من webpack ، أريد أن أتحدث عن إصدارها الطفيف على ما يبدو 4.26.0 في 19 نوفمبر 2018 ، حيث تم تغيير الإصدار الافتراضي من المصغر ، بشكل غير متوقع ودون إعلان الحرب. اعتادت أن تكون حزمة UglifyJS ، والآن تستخدم Terser ، شوكة UglifyES ، وهي فرع من UglifyJS يمكنه ضغط كل من كود ES5 و ES6. ظهر Terser عندما رفض المشرف الرئيسي دعم وتطوير UglifyES. ومع ذلك ، توقفت UglifyJS أيضًا عن التطوير في أغسطس 2018 ، عندما تم إصدار الإصدار الأخير. في مفترق جديد ، قمنا بإصلاح بعض الأخطاء وإعادة تشكيل الكود قليلاً.
واجهة برمجة التطبيقات لهذه المصغرات متوافقة ، لكنها تنتج نتائج ضغط مختلفة. عادةً ما تحدث تغييرات هذا المستوى في التحديثات الرئيسية ، وليس الثانوية فقط. لهذا السبب ، قد لا يهتم العديد من المطورين بالابتكار. بالطبع ، في معظم الحالات ، سيكون كل شيء ناجحًا ، لكن لا أحد يريد أن يصبح الشخص الذي يحصل على أخطاء في إنتاج مشروعه بسبب نظام الإنشاء والتصغير.
هذه القصة كلها دفعتني إلى القيام ببعض الأبحاث الشخصية حول الضغط. إليكم الأسئلة التي طرحتها:
- ما الذي يضغط ES5 أو TerSer أو UglifyJS بشكل أفضل؟
- ما هو التحميل أسرع: نسخة مضغوطة من ES5 من Terser أو من UglifyJS؟
- أي إصدار يزن أكثر: ES5 أو ES6؟ وكيف يؤثر TypeScript على هذا؟
- هل هناك فرق كبير بين الإعدادات الافتراضية والإعدادات اليدوية؟
- وإذا لم يكن webpack؟ من الذي ينتج تجميعًا أصغر ، Rollup أو webpack؟
للبحث ، قمت بتقديم تطبيق React 16 صغيرًا يقدم تطبيق Vue 2 يقدم تطبيق Angular 7 يحتوي على زر واحد بالكامل.
في المجموع ، تم إصدار 695 3 بايت من الكود غير المصغر (720 393 gzip بايت).
ما الذي يضغط ES5 أو TerSer أو UglifyJS بشكل أفضل؟
أخذت آخر UglifyJS المتاحة وأتيت مع حزمة الويب Terser مع خيار ES5 واستخدمت نفس إعدادات الضغط.
| الحجم بالبايت
| الحجم بالبايت (gzip)
|
UglifyJS
| 1050376
| 285،290
|
تيررس
| 1089282
| 292 678
|
خلاصة القول: UglifyJS يضغط بشكل أفضل بنسبة 3.5 ٪ (2.5 ٪ غزيب).
ما هو التحميل أسرع: نسخة مضغوطة من ES5 من Terser أو من UglifyJS؟
قمت بقياس الأداء باستخدام متصفح DevTools Yandex القياسي. لقد قمت بتحميل الصفحة 12 مرة وأخذت قيمة البرمجة النصية (وقت تشغيل البرنامج النصي) ، متجاهلة الأبعاد الثلاثة الأولى.
UglifyJS - 221 مللي ثانية (خطأ 2.8٪).
Terser - 226 مللي ثانية (خطأ 2.7٪).
خلاصة القول: القيم صغيرة جدًا لمثل هذا الخطأ ، ويمكننا اعتبارها واحدة. نخلص أيضًا إلى أن هذه الطريقة غير مناسبة لقياس وقت التحميل.
لم أقم بقياس ومقارنة سرعة الشفرة ، لأن الشفرة المختلفة تعمل بشكل مختلف. يجب على مطوري كل مشروع التحقيق بشكل مستقل في هذه المشكلة.
أي إصدار يزن أكثر: ES6 أو ES5؟ وكيف يؤثر TypeScript على هذا؟
لمقارنة الإصدارين والتركيز فقط على التكنولوجيا ، أخذت
ملحقات بابل وأعدت أربع مجموعات:
- ES5: جميع المكونات الإضافية التي تحمل علامة es2016 + + plugin لـ Object.assign + plugins للإصدارات اللاحقة + الإضافات التجريبية ، يتم تثبيت الهدف في tsconfig في ES5 ؛
- ES5 (ts esnext): جميع المكونات الإضافية التي تحمل علامة es2016 ، + مكون إضافي لـ Object.assign + جميع المكونات الإضافية للإصدارات الأحدث + الإضافات التجريبية ، يتم تعيين الهدف في tsconfig على esnext ؛
- ES6: المكونات الإضافية فقط لـ es2017 والإصدارات الأحدث + المكونات الإضافية التجريبية ، تم تعيين الهدف في tsconfig على ES6 ؛
- ES6 (ts esnext): المكونات الإضافية فقط لـ es2017 والإضافات التجريبية اللاحقة + ، تم تعيين الهدف في tsconfig إلى esnext.
| الحجم بالبايت
| الحجم بالبايت (gzip)
|
ES5
| 1 186 520
| 322 071
|
ES5 (ts esnext)
| 1089282
| 292 678
|
ES6
| 1.087.220
| 292 232
|
ES6 (ts esnext)
| 1.087.220
| 292 232
|
خلاصة القول: إن النسخة المضغوطة من قبل بابل مع رمز زمني للترجمة تحت esnext تزن 97238 بايت (8.2 ٪) أقل. حدث هذا بشكل غير متوقع كثيرًا ، لأن
الزاوي مكتوب في TypeScript ، ولا يمكن لـ Vue and React
في JavaScript Terser ، مثل Uglify ، تجميع قطعة من التعليمات البرمجية غير المستخدمة يتم تسليمها من الزاوي باستخدام برنامج نصي على الويب عند الإنشاء باستخدام حزمة الويب. هذا خطأ تجميع لهذا المثال. في التجمع على مشروع آخر ، قد لا يكون ، والفرق سيكون أصغر بكثير.
يُرى أيضًا أن حجم رمز ES6 أقل من ES5 بمقدار 2062 بايت فقط. في مشروع الحيوانات الأليفة ، حصلت على نتيجة مختلفة تمامًا: رمز ES6 يزيد بنسبة 3-6٪ عن ES5. ويرجع ذلك إلى عدة عوامل ، أهمها:
1. يتم إدراج المساعد بابل في الميراث فئة مرة واحدة ثم يكلف أربعة بايت (ه (أ ، ب)) ، ويستخدم ES6 الميراث الأصلي بتكلفة 15 بايت (الفئة أ يمتد ب).
2. طريقة التصريح عن المتغيرات. في ES5 ، هذه هي vars ، وهي مضغوطة تمامًا. ولكن في ES6 ، يتم السماح والقسائم ، والتي تحافظ على ترتيب التهيئة ولا يتم دمجها مع بعضها البعض.
التصغير العدواني غير الآمن مثل وظائف السهم القسري أو استخدام الإعداد السائب سيساعد على تقليل حجم رمز ES6. كن حذرا والنظر في الدقيقة. على سبيل المثال ، في Firefox ، تكون وظائف السهم
أبطأ أربع مرات من المعتاد ، ولكن في Chromium لا يوجد فرق.
لذلك ، من المستحيل الإجابة بشكل لا لبس فيه على السؤال: تعتمد النتيجة اعتمادًا كبيرًا على الكود وزمن التشغيل المستهدف.
هل هناك فرق كبير بين الإعدادات الافتراضية والإعدادات اليدوية؟
قارن ما إذا كان من الممكن الحصول على حجم ملف أصغر إذا قمت بضبط الإعدادات قليلاً. على سبيل المثال ، نشير إلى أنه يجب تكرار التصغير خمس مرات. بشكل افتراضي ، يمر مرة واحدة فقط.
| الحجم بالبايت
| الحجم بالبايت (gzip)
|
Terser (افتراضي) ES5
| 1097141
| 294 306
|
Terser (يتخطى 5) ES5
| 1 089 312
| 292408
|
قم بإلغاء (افتراضي) ES5
| 1 091 350
| 29445
|
إهمال (يمر 5) ES5
| 1050363
| 284 618
|
خلاصة القول: Uglify مع التصغير خمسة أضعاف أقل من Uglify افتراضيا بنسبة 3.7 ٪ (3.4 ٪ gzip). لذلك ، يجب عليك دائمًا تشديد إعدادات الضغط. بالمناسبة ، لا يعني التصغير خمسة أضعاف أن التجميع سيطول مدة خمس مرات. على سبيل المثال ، في مشروع الاختبار هذا ، يستغرق التصغير المفرد 18 ثانية وخمس مرات - 38 وعشر مرات - 49. أوصي بالبحث التجريبي عن القيمة المثالية لمشروعك ، وبعد ذلك سيتوقف التصغير ولن يتغير الرمز. عادة ما يكون من 5 إلى 10. هناك أيضًا مجموعة من الخيارات الأخرى: التعليقات: الكاذبة تقطع جميع التعليقات حول التراخيص (على الرغم من أن هذه مشكلة قانونية) ، و hoist_funs: وظائف المجموعات الحقيقية تعمل في مكان واحد ، مما يسمح بتحسين الآيات بشكل أفضل. من الناحية المثالية ، تحتاج إلى تجاوز جميع
الإعدادات .
من الذي ينتج تجميعًا أصغر ، Rollup أو webpack؟
Rollup هو أداة تجميع بديلة مع آلية اهتزاز الأشجار المدمجة. بالنسبة للاختبار ، قمت بإنشاء تطبيق على مجموعة التحديثات 0.67.4 باستخدام نفس إعدادات حزمة الويب.
| الحجم بالبايت
| الحجم بالبايت (gzip)
|
مجموعة التحديثات ES5 (Uglify)
| 990 497
| 274 105
|
Rollup ES5 (Terser)
| 995 318
| 272 532
|
webpack ES5 (Uglify)
| 1050363
| 284 618
|
webpack ES5 (Terser)
| 1 089 312
| 292408
|
خلاصة القول: النتيجة من Rollup و Uglify هي 5.6٪ (3.6٪ gzip) أقل.
حدث هذا لعدة أسباب:
1. Webpack يحتوي على عكازات لحالات الحدود. على سبيل المثال ، يلتف
هذا الرمز كل استدعاء دالة من وحدة نمطية أخرى في كائن (). يتم ذلك لمنع نقل السياق للوحدات النمطية دون استخدام صارم للوحدات النمطية مع الاستخدام الصارم. لا تحتاج المشاريع المكتوبة جيدًا دون التبعيات الخاصة بجهات خارجية إلى غلاف ، ولكن في بعض الأحيان لا يتم تضمين التعليمات البرمجية المكتوبة جيدًا في التجميع. وفي هذا الصدد ، تبدو حزمة الويب أكثر موثوقية. Rollap ، بدوره ، يعتقد أن جميع الوحدات النمطية هي وحدات ES6 ، ودائما يتم تنفيذها في الاستخدام الصارم ، لذلك هذه المشكلة ببساطة لا وجود له.
سؤال مهم هو كيف تؤثر عكازات webpack على الأداء. تخيل أننا كتبنا الكود المثالي الذي لا يحتاج إلى أغلفة إضافية ، ولكن مع ذلك ، ستستمر كل مكالمة دالة. يضيف ذلك حملًا صغيرًا للتنفيذ: حوالي مائة من مايكروثانية لكل وظيفة استدعاء في Chromium (عُشر في Firefox).
2. تحتوي حزمة الويب على شريط تشغيل صغير يتحكم في تهيئة الوحدات النمطية وتحميلها. لا يستخدم Rollup wrappers ، ولكن ببساطة يسقط رمز كل الوحدات النمطية في نطاق واحد. تحتوي حزمة الويب على تحسين مماثل ، لكنها لا تعمل مع جميع الوحدات.
ملخص الدراسة
آمل أن يقوم الكثيرون ، بعد قراءة المقال ، بفحص أنظمة الإنشاء الخاصة بهم والتأكد من أنهم يستخدمون جميع الحيل الممكنة للحصول على أفضل ضغط. إنه سريع وسهل.
أولاً ، قم بإعداد مجموعة من TypeScript و Babel بشكل صحيح. دع كل مكون من مكونات التجميع يقوم بعمله الخاص: يقوم أحدهما بالتحقق من الأنواع ، والثاني مسؤول عن التحويل إلى معايير قديمة.
ثانياً ، عند استخدام ES5 ، يمكنك تغيير المصغير مرة أخرى إلى UglifyJS ، لكن تذكر أنه لم يعد مدعومًا.
ثالثًا ، من الأفضل اختيار مجموعة التحديثات للتجميع. ومع ذلك ، ليس في جميع الحالات هذا ممكن بسبب عدم وجود بعض الإضافات. بعد التجميع ، لا تنس التحقق من الوظيفة عن طريق الاختبارات الوظيفية. إذا لم يكن لديك - حان الوقت للبدء في كتابتها.