وحدات ES6 في المتصفح: هل هي جاهزة أم لا؟

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



إذا كان أي شخص لا يعرف - هكذا تبدو.

هناك صفحة index.html:

<!DOCTYPE html>
<html>
  <body>
    <div id="app"></div>
  
    <script type="module" src="index.mjs"></script>
    <!--     "module" -->
  </body>
</html>

هناك ملف index.mjsيمثل وحدة متصلة بالصفحة:

import { doSomething } from './utils.mjs';

doSomething('Make me a sandwich');

تستورد هذه الوحدة بدورها الوظيفة doSomethingمن الوحدة utils.mjs:

export const doSomething = message => {
  console.log('No.');
};

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

تعليق!

حول دعم المتصفح للوحدات النمطية


قبل أن أتحدث عما أفهمه ، أقترح إلقاء نظرة على دعم المتصفح للوحدات النمطية. أكتب هذه المادة في بداية عام 2020 ، لذا فإن مستوى الدعم للوحدات مثير للإعجاب للغاية 90٪.


دعم الوحدات مع المتصفحات وفقًا لموقع caniuse.com

أنا سعيد جدًا بهذه الـ 90٪ (أنا لا آخذ في الاعتبار احتياجات 10٪ من المستخدمين) ، على الرغم من أنك قد ترغب في أن تكون أكثر مسؤولية. ولكن ، حتى مع مراعاة ذلك ، إذا لم يكن مشروعك مصممًا لـ IE أو UC أو Opera Mini ، فإن هذا المستوى من الدعم يعني أن ما يقرب من 100٪ من جمهورك المستهدف سيكون قادرًا على العمل مع مشروعك دون مشاكل.

صحيح أن دعم المستعرض للوحدات النمطية هو البداية فقط. هنا أريد أن أجد الإجابة على ثلاثة أسئلة ظهرت في بداية رحلتي نحو الوحدات:

  • هل استخدام الوحدات النمطية في المتصفحات له أي مزايا؟
  • ماذا عن السلبيات؟
  • أنا متأكد من أن لدي سؤال ثالث ، لكنني الآن لا أتذكره.

دعونا نكتشف ذلك ...

ما هي مزايا استخدام الوحدات في المتصفحات؟


هذا جافا سكريبت خالص! لا يوجد خط أنابيب لمشروع التجميع ، ولا ملف تكوين Webpack المكون من 400 سطر ، ولا يوجد Babel ، ولا مكونات إضافية وإعدادات مسبقة ، ولا 45 وحدة npm إضافية. فقط أنت ورمزك.

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

وبالتالي. مزايا وحدات ES6 هي JavaScript خالصة ، وهذا هو عدم التجميع ، وتكوين المشروع ، وهذا رفض التبعيات التي أصبحت غير ضرورية. ماذا بعد؟ هل هناك شيء آخر؟

لا ، لا أكثر.

ما هي عيوب استخدام الوحدات في المتصفحات؟


▍ مقارنة الوحدات والحزم


عند التفكير في استخدام وحدات ES6 في مستعرض ، فعليك الاختيار بين استخدام الوحدات ووحدات الحزم مثل Webpack أو Parcel أو Rollup.

يمكنك (على الأرجح) استخدام كلاهما ، ولكن في الواقع ، إذا كنت تخطط لتشغيل التعليمات البرمجية من خلال أداة الحزم ، فلا يوجد سبب لاستخدام التصميم <script type="module">لتحميل ملفات الحزم.

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

  • تصغير الرمز النهائي.
  • ميزات جافا سكريبت المتطورة.
  • بناء جملة يختلف عن بناء JavaScript (React ، TypeScript ، إلخ).
  • وحدات Npm.
  • التخزين المؤقت

خذ بعين الاعتبار الفقرات الثلاث الأولى من هذه القائمة بمزيد من التفصيل.

▍ حجم الملف


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

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

يلفت ضغط البيانات انتباهنا إلى مشكلة أخرى: الطريقة التي يتم بها تنظيم الملفات (بمعنى سهولة التطوير) يتم نقلها مباشرة إلى طريقة نقل الملفات عبر الشبكة. والطريقة التي يتم بها تنظيم الملفات أثناء التطوير لا تتوافق بالضرورة مع الطريقة التي تريد رؤيتها بها في الموقع. على سبيل المثال ، قد تكون 150 وحدة (ملفات) منطقية أثناء العمل على مشروع. ويمكن تبرير نفس المواد المنقولة إلى المتصفح لتنظيمها في 12 حزمة.

سأشرح هذه الفكرة. أنا لا أتحدث عن حقيقة أن استخدام الوحدات يعني أنه لا يمكن تجميع الملفات وتصغيرها (حقيقة أنه لا يمكن القيام بذلك هو وهم). أعني فقط أنه لا معنى للقيام بالأمرين.

نعم ، هذه ملاحظة مضحكة. في طلبي ، حتى كتبت هذا القسم ، تم استخدام الوحدات (أؤكد!). لقد قمت بتثبيت Parcel لحساب حجم التجميع الصحيح. والآن لا أرى أي سبب للعودة إلى الوحدات العادية. حسنًا ، أليس هذا مثيرًا للاهتمام!

ifeحياة بدون شفط


لقد اعتدت على مر السنين على استخدام أحدث تراكيب بناء جافا سكريبت ، وأداة بابل الرائعة ، التي تحولها إلى رمز يفهمه كل المتصفحات. لقد اعتدت على ذلك كثيرًا لدرجة أنني نادرًا ما كنت أفكر على الأقل في دعم المتصفح (بالطبع ، باستثناء DOM و CSS).

عندما حاولت لأول مرة type=«module»، كنت سأفعل كل شيء بنفسي. كان هدفي هو المتصفحات الجديدة ، لذلك اعتقدت أنه يمكنني استخدام جافا سكريبت الحديثة ، التي اعتدت عليها.

لكن الحقيقة لم تكن وردية. حاول الإجابة على الأسئلة التالية بسرعة ودون النظر إلى أي مكان. هل يدعم EdgeflatMap()؟؟؟ هل يدعم Safari التخصيص المدمر (الأشياء والمصفوفات)؟ هل يدعم Chrome الفواصل بعد حجج الدالة الأخيرة؟ هل يدعم فايرفوكس الأسي؟

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

وهذا يعني أيضًا أنني لن أتمكن من استخدام ابتكار جافا سكريبت الأكثر بروزًا منذ ظهور أسلوب الصفيف slice()- ما يسمى عامل التسلسل الاختياري . لقد استخدمت التصاميم السحرية مثلprop?.valueحوالي شهر واحد تقريبًا (منذ اللحظة التي بدأت فيها أداة Create React App في دعمها بدون أي إعدادات إضافية). ولكن من غير المريح لي العمل بدونهم.

▍ أعباء التخزين المؤقت


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

كما أنت متأكد ، كما تعلم ، عندما تتم معالجة المواد باستخدام أداة تجميع ، يحصل كل ملف من الملفات الناتجة على اسم فريد - نوعًا ما index.38fd9e.js. لا تتغير محتويات ملف بهذا الاسم مطلقًا (أبدًا). لذلك ، يمكن تخزينه مؤقتًا بواسطة المتصفح لفترة غير محدودة. إذا تم تنزيل هذا الملف مرة واحدة ، فلن تضطر إلى تنزيله مرة أخرى.

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

يتم تحميل الوحدات باستخدام تصميم مثل<script type="module" src="index.mjs"></script>. لا يتم استخدام التجزئة في اسم الملف. كيف ، في هذه الحالة ، من المفترض أن يبلغ المتصفح عن مكان تنزيله index.mjs- من ذاكرة التخزين المؤقت أو من الشبكة؟

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

  • يجب عليك تعيين عنوان كل الإجابات cache-controlعلى قيمة no-cache. بشكل لا يصدق ، لا يعني عدم وجود ذاكرة تخزين مؤقت "عدم التخزين المؤقت". هذا يعني أنه يجب تخزين الملف في ذاكرة التخزين المؤقت ، ولكن لا يجب استخدام الملف "لتلبية طلب لاحق دون التحقق بنجاح على الخادم المصدر."
  • ETag. — () , , , . , 38fd9e .
  • CDN- , . ETag . . CDN- . ( ETag) . (, , Firebase).
  • -, , « » . , , , , .

ونتيجة لذلك ، عندما يعيد الزائر زيارة الموقع ، سيقول المتصفح: "أحتاج إلى تنزيل الملف index.mjs. أرى أن هذا الملف موجود بالفعل في ذاكرة التخزين المؤقت ، ETag الخاص به 38fd9e. سأطلب هذا الملف من الخادم ، ولكن سأخبره أن يرسله إلي فقط إذا لم يكن ETag الخاص به ليس كذلك 38fd9e. " سيعترض عامل الخدمة هذا الطلب ، ويتجاهل ETag ويعيده index.mjsمن ذاكرة التخزين المؤقت الخاصة به (تم إدخال هذا الملف في ذاكرة التخزين المؤقت عندما تم تحميل الصفحة آخر مرة). ثم سيقوم عامل الخدمة بإعادة توجيه الطلب إلى الخادم. سيقوم الخادم إما بإعادة رسالة تفيد بأن الملف لم يتغير ، أو ملف سيتم تخزينه في ذاكرة التخزين المؤقت.

في رأيي ، كل هذا مزعج للغاية.

الآن ، إذا كنت مهتمًا ، فإن رمز عامل الخدمة:

self.addEventListener('fetch', e => {
  e.respondWith(
    (async () => {
      //       
      const cacheResponse = await caches.match(e.request);
      
      //   (),   
      // (ETag-    )
      fetch(e.request).then(fetchResponse => {
        caches
          .open(CACHE_NAME)
          .then(cache => cache.put(e.request, fetchResponse));
      });
      
      if (cacheResponse) return cacheResponse;
      
      return fetch(e.request);
    })()
  );
});

كنت كسولًا ، لذلك لم أدرس ولم أستخدم أحدث خاصية FetchEvent.navigationPreload . والحقيقة هي أنني في ذلك الوقت أمضيت وقتًا في التخزين المؤقت أكثر من كتابة طلب (لمعلوماتك ، قضيت 10 و 11 ساعة في هذه الأمور ، على التوالي).

نعم ، أود أن أشير إلى أن اقتراح "بطاقة الاستيراد" يهدف إلى حل بعض المشكلات الموضحة أعلاه. يسمح لك بتنظيم شيء مثل رسم الخرائط index.jsعلى index.38fd9e.mjs. ولكن لإنشاء تجزئة ، على أي حال ، أنت بحاجة إلى نوع من خط التجميع ، يجب تضمين بطاقات الاستيراد في ملف HTML. هذا يعني أن هناك حاجة إلى أداة تجميع هنا ... في الواقع ، في هذه الحالة ، لم تعد هناك حاجة إلى الوحدات النمطية في المتصفح.

ونتيجة لذلك ، على الرغم من أنه كان من المثير للاهتمام فهم كل هذا ، إلا أنه يمكن مقارنته بالطريقة التي كنت أقودها في كل مكان في دورة أحادية لمدة عام كامل. لن أفعل هذا بعد الآن.

ولكن ربما لا يستخدم الجميع الحزم؟


لقد كتبت هذه المادة على افتراض أن الجميع يكتب التعليمات البرمجية في وحدات ، باستخدام بنيات import/exportأو require، ثم جمع التعليمات البرمجية في حزم الإنتاج باستخدام Webpack أو Grunt أو Gulp أو شيء من هذا القبيل.

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

ملخص


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

لسوء الحظ ، لا يساهم استخدام الوحدات النمطية في المستعرضات في أحدهما أو الآخر.

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

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

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

القراء الأعزاء! هل استخدمت وحدات ES6 في متصفحك؟


All Articles