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

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

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

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

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

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

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

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

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

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

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

המגבלה הזו מקבילה להגבלה דומה שחלה על השימוש ב-importScripts(). קריאות דינמיות ל-importScripts() לא פועלות בתוך שירות עובד, וכל הקריאות ל-importScripts(), שהן קריאות סינכרוניות מטבען, חייבות להסתיים לפני ששירות העובד משלים את השלב 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 ואילך תומכים בייבוא מפות, אבל אי אפשר להשתמש בהם כרגע עם שירותי עובדים.

תמיכה בדפדפנים

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

ב-Safari נוספה תמיכה בגרסה ה-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 ב-service worker, אבל נכון לעכשיו זה לא המצב.

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

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

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