وحدات ES في مشغّلي الخدمات

بديل حديث لواجهة importScripts()‎

الخلفية

وحدات ES كانت من المفضّلات لدى المطوّرين منذ فترة. بالإضافة إلى عدد من المزايا الأخرى، فإنها تعِد تنسيق وحدات عامة يمكن من خلاله إصدار الرمز المشترك مرة واحدة وتشغيله في المتصفحات وفي بيئات تشغيل بديلة، مثل Node.js. على الرغم من أنّ جميع المتصفحات الحديثة تتيح استخدام بعض وحدات ES، إلا أنّها لا تتيح استخدامها في كل مكان يمكن فيه تنفيذ الرمز. على وجه التحديد، بدأنا للتو في إتاحة إمكانية استيراد وحدات ES داخل خدمة عامل التشغيل في ال browser.

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

حالات الاستخدام

إنّ حالة الاستخدام المثالية لوحدات ES داخل مشغّلي الخدمات هي تحميل مكتبة حديثة أو رمز إعداد تتم مشاركته مع بيئات تشغيل أخرى متوافقة مع وحدات ES.

كانت محاولة مشاركة الرمز بهذه الطريقة قبل وحدات ES تتطلّب استخدام تنسيقات وحدات "عالمية" قديمة، مثل UMD، التي تتضمّن نماذج أساسية غير مطلوبة، وكتابة رمز يُجري تغييرات على المتغيّرات المعروضة بشكل عام.

يمكن أن تؤدي النصوص البرمجية التي تم استيرادها من خلال وحدات ES إلى بدء عملية تعديل عامل الخدمة في حال تغيّر محتوياتها، ما يتطابق مع السلوك importScripts().

القيود الحالية

عمليات الاستيراد الثابتة فقط

يمكن استيراد وحدات ES بطريقتَين: إما بشكل ثابت، باستخدام بنية import ... from '...'، أو بشكل ديناميكي، باستخدام الطريقة import(). داخل عامل الخدمة، لا تتوفّر حاليًا سوى البنية static .

هذا التقييد مشابه لمحاولة فرض قيود مماثلة على استخدام importScripts(). لا تعمل طلبات importScripts() الديناميكية داخل عامل الخدمة، ويجب إكمال جميع طلبات importScripts() التي تتم بشكلٍ متزامن بشكلٍ أساسي قبل أن يكمل عامل الخدمة مرحلة install. يضمن هذا القيد أنّ المتصفّح يعرف كل رمز JavaScript المطلوب لتنفيذ worker الخدمة ويصعُب عليه تخزينه مؤقتًا بشكل ضمني أثناء التثبيت.

في النهاية، قد تتم إزالة هذا الحظر ويُسمح بعمليات استيراد وحدة ES الديناميكية. في الوقت الحالي، تأكَّد من استخدام البنية الثابتة فقط داخل عامل خدمة.

ماذا عن العمال الآخرين؟

إنّ استخدام وحدات ES في "العمال المخصّصين"، أي تلك المُنشأة باستخدام new Worker('...', {type: 'module'})، هو أكثر انتشارًا، وقد أصبح متاحًا في Chrome وEdge منذ الإصدار 80، بالإضافة إلى الإصدارات الحديثة من Safari. يتيح العاملون المتخصّصون استيراد وحدات ES الثابتة والديناميكية.

يتوافق Chrome وEdge مع وحدات ES في العاملين المشتركين منذ الإصدار 83، ولكن لا يتوافق أي متصفّح آخر في الوقت الحالي.

لا تتوفّر إمكانية استيراد الخرائط

تسمح خرائط الاستيراد لشدَّود التشغيل بإعادة كتابة محدّدات الوحدات، على سبيل المثال، لإضافة عنوان URL لشبكة توصيل المحتوى (CDN) المفضّلة التي يمكن من خلالها تحميل وحدات ES.

على الرغم من أنّ Chrome وEdge الإصدار 89 والإصدارات الأحدث يتوافقان مع استيراد الخرائط، فإنه لا يمكن استخدامهما حاليًا مع معالجي الخدمة.

دعم المتصفح

تتوفّر وحدات ES في مهام الخدمة في Chrome وEdge اعتبارًا من الإصدار 91.

أضاف متصفّح Safari توافقًا مع إصدار Technology Preview 122، ومن المتوقَّع أن يرى المطوّرون هذه الوظيفة في الإصدار الثابت من Safari في المستقبل.

مثال على الرمز

هذا مثال أساسي لاستخدام وحدة ES مشتركة في سياق window لتطبيق الويب، وفي الوقت نفسه تسجيل مشغّل خدمات يستخدم وحدة ES نفسها:

// Inside config.js:
export const cacheName = 'my-cache';
// Inside your web app:
<script type="module">
  import {cacheName} from './config.js';
  // Do something with cacheName.

  await navigator.serviceWorker.register('es-module-sw.js', {
    type: 'module',
  });
</script>
// Inside es-module-sw.js:
import {cacheName} from './config.js';

self.addEventListener('install', (event) => {
  event.waitUntil((async () => {
    const cache = await caches.open(cacheName);
    // ...
  })());
});

التوافق مع الأنظمة القديمة

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

لاستيعاب المتصفحات التي لا تتضمّن ميزة مدمجة، يمكنك تشغيل ملف برمجي لعامل الخدمة من خلال أداة تجميع متوافقة مع وحدات ES لإنشاء عامل خدمة يتضمّن كل رمز الوحدة مضمّنًا، وسيعمل في المتصفحات القديمة. بدلاً من ذلك، إذا كانت الوحدات التي تحاول استيرادها متوفرة مجمّعة في تنسيقَي IIFE أو UMD، يمكنك استيرادها باستخدام importScripts().

بعد توفّر نسختَين من worker الخدمة، إحداهما تستخدِم وحدات ES والأخرى لا تستخدِمها، عليك رصد ما يتوافق مع المتصفّح الحالي وتسجيل نص worker الخدمة المقابل. إنّ أفضل الممارسات لرصد الدعم قيد المراجعة حاليًا، ولكن يمكنك متابعة المناقشة في هذه المشكلة على GitHub للحصول على اقتراحات.

_صورة لفلاديو باونوفيتش على Unsplash_