מודולים של ES ב-Service Workers

חלופה מודרנית ל-ImportScripts().

רקע

המודולים של ES הם הבחירה המועדפת על מפתחים כבר לא מעט זמן. בנוסף לכמה יתרונות אחרים, הם מציעים את ההבטחה לפורמט של מודול אוניברסלי, שבו אפשר לפרסם קוד משותף פעם אחת ולפעול בדפדפנים ובסביבות ריצה חלופיות כמו Node.js. כל הדפדפנים המודרניים מציעים תמיכה מסוימת במודול ES, אבל לא כולם מציעים תמיכה בכל מקום שבו אפשר להריץ את הקוד. באופן ספציפי, התמיכה בייבוא מודולים של ES בתוך ה-service worker של הדפדפן הופכת לזמינה יותר.

מאמר זה מפרט את המצב הנוכחי של התמיכה במודול ES ב-Service Workers בדפדפנים נפוצים, כמה נקודות שכדאי להימנע מהן, ושיטות מומלצות לשליחת קוד Service Worker שתואם לאחור.

תרחישים לדוגמה

התרחיש האידיאלי למודולים של ES בתוך Service Workers הוא לטעון ספרייה מודרנית או קוד תצורה שמשותף עם זמני ריצה אחרים שתומכים במודולים של ES.

ניסיון לשתף קוד בצורה הזו לפני המודולים של ES, שכלל שימוש בפורמטים ישנים יותר של מודול 'אוניברסלי', כמו UMD, שכוללים תבנית סטנדרטית לא נחוצה, וכתיבת קוד שביצע שינויים במשתנים שנחשפו באופן גלובלי.

סקריפטים שיובאו דרך מודולים של ES יכולים להפעיל את תהליך העדכון של Service Worker אם התוכן שלהם משתנה, בהתאם להתנהגות של importScripts().

מגבלות נוכחיות

ייבוא סטטי בלבד

אפשר לייבא מודולים של ES באחת משתי דרכים: באופן סטטי, באמצעות התחביר import ... from '...' או באופן דינמי, באמצעות השיטה import(). בתוך קובץ שירות (service worker), כרגע יש תמיכה רק בתחביר הסטטי.

הגבלה זו מקבילה להגבלה דומה שחלה על השימוש ב-importScripts(). קריאות דינמיות ל-importScripts() לא פועלות בתוך Service Worker, וכל הקריאות של importScripts(), שהן סינכרוניות מטבען, צריכות להסתיים לפני שה-Service Worker מסיים את השלב install. ההגבלה הזו מבטיחה שהדפדפן יודע את כל קוד ה-JavaScript שנדרש להטמעה של Service Worker במהלך ההתקנה, ושאפשר לשמור אותו במטמון באופן מרומז.

בסופו של דבר, יכול להיות שההגבלה הזו תוסר ויכול להיות שנאפשר ייבוא דינמי של מודולים של ES. בינתיים, הקפידו להשתמש בתחביר הסטטי רק ב-Service Worker.

מה לגבי עובדים אחרים?

התמיכה במודולים ייעודיים של ES – שנוצרו באמצעות new Worker('...', {type: 'module'}) – נרחבת יותר, ונתמכת ב-Chrome וב-Edge מאז גרסה 80, וגם מגרסאות אחרונות של Safari. ייבוא של מודולים סטטיים ודינמיים של ES נתמך בעובדים ייעודיים.

Chrome ו-Edge תמכו במודולים של ES בעובדים משותפים מאז גרסה 83, אבל כרגע אין דפדפנים אחרים שתומכים בכך.

אין תמיכה בייבוא מפות

ייבוא מפות מאפשר לסביבות זמן ריצה לשכתב את המפרט של מודולים, לדוגמה, להוסיף בתחילת כתובת ה-URL של CDN מועדף שממנו אפשר לטעון את המודולים של ES.

Chrome ו-Edge גרסה 89 ואילך תומכים במפות ייבוא, אבל כרגע לא ניתן להשתמש בהן עם Service Workers.

תמיכת דפדפן

המודולים של ES ב-service worker נתמכים ב-Chrome וב-Edge, החל מגרסה 91.

ל-Safari נוספה תמיכה בגרסת 122 של התצוגה המקדימה של הטכנולוגיה, והמפתחים אמורים לראות את הפונקציונליות הזו בגרסה היציבה של Safari בעתיד.

קוד לדוגמה

זוהי דוגמה בסיסית לשימוש במודול ES משותף בהקשר window של אפליקציית אינטרנט, תוך רישום של קובץ שירות (service worker) שמשתמש באותו מודול 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 ב-service worker, אבל זה לא נכון נכון לעכשיו.

כדי להתאים לדפדפנים שאין בהם תמיכה מובנית, אפשר להריץ את הסקריפט של Service worker דרך bundler תואם למודול ES כדי ליצור קובץ שירות (service worker) שכולל את כל קוד המודול שמוטבע בו, ויעבוד בדפדפנים ישנים יותר. לחלופין, אם המודולים שאתם מנסים לייבא כבר זמינים בחבילה בפורמטים IIFE או UMD, תוכלו לייבא אותם באמצעות importScripts().

אחרי שיהיו לכם שתי גרסאות זמינות של Service Worker – אחת שמשתמשת במודולים של ES והשנייה לא. תצטרכו לזהות במה הדפדפן הנוכחי תומך, ולרשום את הסקריפט של Service Worker התואם. השיטות המומלצות לזיהוי מקורות תמיכה נמצאות כרגע בתנופה, אבל תוכלו להיעזר בדיון שמופיע בבעיה הזו ב-GitHub כדי לקבל המלצות.

_צילום של Vlado Paunovic ב-UnFlood_