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

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

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

  • הודעה לדף על כך שמותקנת גרסה חדשה של ה-Service Worker, כדי שהדף יוכל להציג למשתמש את הלחצן "Update toרענן" (עדכון לרענון) על מנת לגשת לפונקציונליות החדשה באופן מיידי.
  • הודעה למשתמש על שינוי בנתונים שנשמרו במטמון בצד של קובץ השירות (service worker), על ידי הצגת חיווי כמו: "האפליקציה מוכנה עכשיו לעבודה במצב אופליין", או "גרסה חדשה של התוכן זמינה".
תרשים של קובץ שירות (service worker) שמתקשר עם הדף כדי לשלוח עדכון.

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

מקרי ייצור

טינדר

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

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

סקווש

ב-Squoosh PWA, כש-Service Worker שומר במטמון את כל הנכסים הנחוצים כדי שהוא יפעל אופליין, הוא שולח הודעה לדף עם ההודעה " Ready to workקל במצב אופליין" , המיידע את המשתמש על התכונה:

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

שימוש בתיבת עבודה

האזנה לאירועים במחזור החיים של Service Worker

workbox-window מספק ממשק פשוט להאזנה לאירועים חשובים במחזור החיים של Service Worker. מאחורי הקלעים, הספרייה משתמשת בממשקי API בצד הלקוח כמו updatefound ו-statechange, והיא מספקת פונקציות event listener ברמה גבוהה יותר באובייקט 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 לאפשרויות האסטרטגיה בצד של קובץ השירות:

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 הבאים של הדפדפן כדי להטמיע "עדכונים לשידור":

ממשק 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 הזה.

ממשק API של לקוח

Client API מספק דרך ישירה לתקשורת עם מספר לקוחות מה-Service Worker, על ידי חזרה על מערך של אובייקטים של Client.

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

// 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'});
  }
});

הדף מיישם handler של הודעות כדי ליירט את ההודעות האלה:

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

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

ערוץ הודעות

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

const messageChannel = new MessageChannel();

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

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

השלבים הבאים

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

דפוסים נוספים של תקשורת Windows ו-Service Worker:

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