שידור עדכונים לדפים עם 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) מהדף ('מותקן', 'מבוקר' ו'מופעל'). כך, כש-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-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 ולהטמיע handler של הודעה כדי לקבל הודעות.

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

// 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, אבל לא כל השיטות שלו נתמכות. לפני השימוש, כדאי לבדוק את תמיכת הדפדפן.

ערוץ הודעות

כדי להשתמש ב-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 תהיה מורכבת יותר בגלל הצורך לאתחל את היציאות, אבל כל הדפדפנים העיקריים תומכים בה.

השלבים הבאים

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

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

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