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

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

רקע

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

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

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

התרחיש לדוגמה האידיאלי למודולים של ES בתוך Service Worker הוא לטעון ספרייה מודרנית או קוד תצורה שמשותף עם סביבות זמן ריצה אחרות שתומכות במודולים של 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 בעובדים 'ייעודיים' רחבים יותר, ונתמכת ב-Chrome וב-Edge החל מגרסה 80 וגם בגרסאות האחרונות של Safari.new Worker('...', {type: 'module'}) עובדים ייעודיים תומכים גם בייבוא של מודול ES סטטי וגם בייבוא דינמי.

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

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

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

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

תמיכת דפדפן

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

ב-Safari נוספה תמיכה בגרסה ה-Preview 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 Workers, אבל נכון לכתיבה, זה לא נכון.

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

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

_תמונה מאת Vlado Paunovic ב-Unbounce_