עובדי שירות חדשים יותר, כברירת מחדל

ג'ף פוזניק
ג'ף פוזניק

tl;dr

החל מגרסה Chrome 68, בקשות HTTP שבודקות עדכונים לסקריפט של Service Worker לא ימולאו יותר באמצעות מטמון ה-HTTP כברירת מחדל. האפשרות הזו פועלת סביב בעיה נפוצה למפתחים, שבה הגדרת כותרת Cache-Control לא מכוונת בסקריפט של Service Worker עלולה לגרום לעיכובים בעדכונים.

אם כבר בחרתם שלא לשמור במטמון HTTP עבור הסקריפט /service-worker.js באמצעות הצגתו באמצעות Cache-Control: max-age=0, לא אמורים להופיע שינויים בגלל התנהגות ברירת המחדל החדשה.

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

רקע

בכל פעם שמנווטים לדף חדש שנמצא בהיקף של קובץ שירות (service worker), קוראים לו registration.update() ב-JavaScript באופן מפורש, או כש-Service Worker "מתעורר" דרך אירוע push או sync, הדפדפן יבקש במקביל את משאב ה-JavaScript שהועבר במקור אל הקריאה navigator.serviceWorker.register(), כדי לחפש עדכונים בסקריפט של קובץ השירות (service worker).

למטרת המאמר הזה, נניח שכתובת ה-URL שלו היא /service-worker.js ושהיא מכילה קריאה אחת אל importScripts(), שטוענת קוד נוסף שפועל בתוך קובץ השירות (service worker):

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

מה משתנה?

בגרסאות שלפני Chrome 68, בקשת העדכון של /service-worker.js תתבצע דרך מטמון ה-HTTP (כמו רוב האחזורים). כלומר, אם הסקריפט נשלח במקור עם Cache-Control: max-age=600, העדכונים במהלך 600 השניות הבאות (10 דקות) לא יועברו לרשת, ולכן יכול להיות שהמשתמש לא יקבל את הגרסה העדכנית ביותר של קובץ השירות (service worker). עם זאת, אם הערך של max-age היה גדול מ-86,400 (24 שעות), המערכת תתייחס אליו כאילו היה 86,400 כדי שהמשתמשים לא ייתקעו עם גרסה מסוימת לתמיד.

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

updateViaCache

המפתחים יכולים עכשיו להעביר אפשרות חדשה בקריאה ל-navigator.serviceWorker.register(): הפרמטר updateViaCache. הפונקציה מקבלת אחד משלושה ערכים: 'imports', 'all' או 'none'.

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

  • אם המדיניות מוגדרת לערך 'imports', מטמון ה-HTTP אף פעם לא יהיה בשימוש במהלך חיפוש עדכונים לסקריפט /service-worker.js, אבל תתבצע בדיקה שלו במהלך אחזור סקריפטים מיובאים (path/to/import.js, בדוגמה שלנו). זוהי ברירת המחדל, והיא מתאימה להתנהגות שמתחילה ב-Chrome 68.

  • אם המדיניות מוגדרת לערך 'all', המערכת תשתמש במטמון ה-HTTP בעת שליחת בקשות גם לסקריפט /service-worker.js ברמה העליונה וגם לסקריפטים שיובאו בתוך ה-Service Worker, כמו path/to/import.js. האפשרות הזו תואמת להתנהגות הקודמת ב-Chrome, ב-Chrome 68.

  • אם המדיניות מוגדרת לערך 'none', לא ייעשה שימוש במטמון ה-HTTP בעת שליחת בקשות ל-/service-worker.js שברמה העליונה או לסקריפטים מיובאים כמו ה-path/to/import.js ההיפותטי.

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

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

חיפוש עדכונים לסקריפטים מיובאים

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

הדרך היחידה לאלץ קובץ שירות (service worker) שכבר מותקן לאסוף שינויים בסקריפט מיובא היא לשנות את כתובת ה-URL של הסקריפט, בדרך כלל על ידי הוספת ערך semver (למשל importScripts('https://example.com/v1.1.0/index.js')) או באמצעות הוספה של גיבוב (hash) של התוכן (למשל importScripts('https://example.com/index.abcd1234.js')). שינוי של כתובת ה-URL המיובאת הוא ביצוע השינוי של תוכן הסקריפט של Service Worker ברמה העליונה, שגורם לשינוי התוכן של קובץ ה-service worker.

החל מ-Chrome 78, בכל פעם שתבוצע בדיקת עדכון לקובץ Service Worker ברמה העליונה, יתבצעו באותו זמן בדיקות כדי לקבוע אם התוכן של סקריפטים מיובאים השתנה. בהתאם לכותרות Cache-Control שבשימוש, יכול להיות שבדיקות הסקריפטים המיובאות ימולאו על ידי מטמון ה-HTTP אם updateViaCache מוגדר ל-'all' או ל-'imports' (זהו ערך ברירת המחדל), או שהבדיקות עשויות להתבצע ישירות מול הרשת אם ב-updateViaCache מוגדר הערך 'none'.

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

ההתנהגות של Chrome 78 תואמת לזו ש-Firefox הטמיע לפני כמה שנים, ב-Firefox 56. Safari כבר מטמיע את ההתנהגות הזו גם כן.

מה המפתחים צריכים לעשות?

אם בחרתם לבטל את ההסכמה לשמירה במטמון של HTTP עבור הסקריפט /service-worker.js באמצעות הצגתו עם Cache-Control: max-age=0 (או ערך דומה), לא אמורים להיות שינויים בגלל ההתנהגות החדשה שמוגדרת כברירת המחדל.

אם בכל זאת אתם מפעילים את הסקריפט של /service-worker.js כששמירת HTTP במטמון מופעלת, באופן מכוון או מפני שזוהי רק ברירת המחדל של סביבת האירוח, ייתכן שתתחילו לראות עלייה חדה בבקשות HTTP נוספות מסוג /service-worker.js שבוצעו בשרת שלכם. אלו הן בקשות ששימשו למילוי על ידי מטמון ה-HTTP. כדי להמשיך לאפשר לערך הכותרת Cache-Control להשפיע על העדכניות של /service-worker.js, תצטרכו להתחיל באופן מפורש להגדיר את updateViaCache: 'all' במהלך הרישום של קובץ השירות (service worker).

יכול להיות שיש הרבה משתמשים בגרסאות דפדפן ישנות יותר, ולכן כדאי להמשיך להגדיר את כותרת ה-HTTP Cache-Control: max-age=0 בסקריפטים של Service Worker, למרות שדפדפנים חדשים יותר עשויים להתעלם מהם.

המפתחים יכולים להשתמש בהזדמנות הזו כדי להחליט אם הם רוצים לבטל עכשיו באופן מפורש את הסקריפטים המיובאים שלהם במטמון של HTTP, ולהוסיף את updateViaCache: 'none' לרישום של קובץ השירות (service worker) במקרה הצורך.

הצגת סקריפטים מיובאים

החל מ-Chrome 78, יכול להיות שמפתחים יראו יותר בקשות HTTP נכנסות למשאבים שנטענים דרך importScripts(), כי עכשיו נבדוק אם יש עדכונים.

כדי למנוע את תנועת ה-HTTP הנוספת הזו, צריך להגדיר כותרות Cache-Control לטווח ארוך כשמציגים סקריפטים שכוללים semver או גיבוב (hash) בכתובות ה-URL שלהם, ולהסתמך על התנהגות ברירת המחדל updateViaCache של 'imports'.

לחלופין, אם רוצים שהסקריפטים המיובאים ייבדקו אם יש עדכונים תכופים, הקפידו להציג אותם באמצעות Cache-Control: max-age=0 או להשתמש ב-updateViaCache: 'none'.

קריאה נוספת

"The Service Worker Lifecycle" (מחזור החיים של Service Worker) ו"שיטות מומלצות לשמירה על המטמון ו-max-age gotchas", שניהם מאת ג'ייק ארצ'יבלד, מומלצים לכל המפתחים שפורסים כל דבר באינטרנט.