שידור עדכונים לדפים עם Service Workers

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

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

  • להודיע לדף כשגרסה חדשה של ה-service worker הותקנה, כדי שהדף יוכל להציג למשתמש את הלחצן עדכון לרענון כדי לגשת לפונקציונליות החדשה באופן מיידי.
  • להודיע למשתמש על שינוי בנתונים שנשמרו במטמון שהתרחש בצד של ה-service worker, על ידי הצגת אינדיקציה, כמו: "האפליקציה מוכנה עכשיו לעבודה אופליין" או "יש גרסה חדשה של התוכן".
תרשים שבו מוצג עובד שירות שמתקשר עם הדף כדי לשלוח עדכון.

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

בקשות תמיכה בסביבת ייצור

Tinder

אפליקציית Tinder ל-PWA משתמשת ב-workbox-window כדי להאזין לדפים לרגעים חשובים במחזור החיים של ה-service worker ('מותקן', 'מוגדר' ו'מופעל'). כך, כשעומד להיכנס לפעולה עובד שירות חדש, הוא מציג באנר עם הכיתוב עדכון זמין כדי שהמשתמשים יוכלו לרענן את אפליקציית ה-PWA ולגשת לתכונות העדכניות ביותר:

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

Squoosh

ב-Squoosh PWA, כשעובד השירות שומר במטמון את כל הנכסים הנחוצים כדי שהאפליקציה תפעל במצב אופליין, הוא שולח הודעה לדף כדי להציג הודעה קופצת עם הכיתוב 'מוכן לעבודה במצב אופליין', כדי להודיע למשתמש על התכונה:

צילום מסך של הפונקציונליות 'מוכנה לעבודה אופליין' באפליקציית האינטרנט של Squoosh.
ב-PWA של Squoosh, קובץ השירות משדר עדכון לדף כשהמטמון מוכן, והדף מציג את ההודעה 'מוכן לעבודה במצב אופליין'.

שימוש ב-Workbox

האזנה לאירועים במחזור החיים של שירות ה-worker

workbox-window מספק ממשק פשוט להאזנה לאירועים חשובים במחזור החיים של קובץ השירות. בספרייה נעשה שימוש בממשקי API בצד הלקוח, כמו updatefound ו-statechange, ומספקים מאזינים לאירועים ברמה גבוהה יותר באובייקט workbox-window, כדי להקל על המשתמש לצרוך את האירועים האלה.

קוד הדף הבא מאפשר לזהות בכל פעם שגרסה חדשה של ה-service worker מותקנת, כדי שתוכלו להודיע על כך למשתמש:

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

עדכון הדף לגבי שינויים בנתוני המטמון

החבילה Workbox‏ workbox-broadcast-update מספקת דרך סטנדרטית להודיע ללקוחות בחלון שהתגובה ששמורה במטמון עודכנה. השיטה הזו משמשת בדרך כלל יחד עם השיטה StaleWhileRevalidate.

כדי לשדר עדכונים, מוסיפים את הערך broadcastUpdate.BroadcastUpdatePlugin לאפשרויות האסטרטגיה בצד של ה-service worker:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

באפליקציית האינטרנט, אפשר להאזין לאירועים האלה באופן הבא:

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

שימוש בממשקי API של דפדפנים

אם הפונקציונליות של Workbox לא מספיקה לצרכים שלכם, תוכלו להשתמש בממשקי ה-API הבאים לדפדפנים כדי להטמיע 'עדכונים לשידור':

Broadcast Channel API

קובץ השירות יוצר אובייקט BroadcastChannel ומתחיל לשלוח אליו הודעות. כל הקשר (למשל דף) שמעוניין לקבל את ההודעות האלה יכול ליצור אובייקט BroadcastChannel ולהטמיע בורר הודעות כדי לקבל הודעות.

כדי להודיע לדף כשמתקין שירות עבודה חדש, משתמשים בקוד הבא:

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

הדף מקשיב לאירועים האלה על ידי הרשמה ל-sw-update-channel:

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

זוהי טכניקה פשוטה, אבל המגבלה שלה היא תמיכת הדפדפן: נכון לזמן כתיבת המאמר, Safari לא תומך ב-API הזה.

Client API

Client API מספק דרך פשוטה לתקשר עם מספר לקוחות מה-service worker, על ידי איטרציה על מערך של אובייקטים מסוג Client.

כדי לשלוח הודעה לכרטיסייה האחרונה שבה התמקדו, משתמשים בקוד הבא של עובד השירות:

// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    // Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});

בדף מוטמע טיפול בהודעות כדי ליירט את ההודעות האלה:

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

ממשק ה-API ללקוח הוא פתרון מצוין למקרים כמו שידור מידע לכמה כרטיסיות פעילות. כל הדפדפנים העיקריים תומכים ב-API, אבל לא כל השיטות שלו נתמכות. לפני שמשתמשים ב-Google Fonts, צריך לבדוק את תמיכת הדפדפן.

ערוץ הודעות

כדי להשתמש ב-Message Channel, צריך לבצע שלב הגדרה ראשוני: העברת יציאה מהדף ל-service worker כדי ליצור ביניהם ערוץ תקשורת. הדף יוצר מופע של אובייקט MessageChannel ומעביר יציאה לקובץ השירות דרך הממשק postMessage():

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

הדף מקשיב להודעות על ידי הטמעת טיפול באירוע onmessage באותו יציאה:

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

קובץ ה-service worker מקבל את היציאה ושומר הפניה אליה:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

מנקודה זו ואילך, הוא יכול לשלוח הודעות לדף באמצעות קריאה ל-postMessage() בהפניה לשקע:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

יכול להיות שהטמעת MessageChannel תהיה מורכבת יותר בגלל הצורך לאתחל את היציאות, אבל כל הדפדפנים העיקריים תומכים בה.

השלבים הבאים

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

דפוסים נוספים של תקשורת בין חלון לבין עובד שירות זמינים במאמרים הבאים:

מקורות מידע נוספים