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

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

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

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

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

תרחישים בסביבת ייצור

טינדר

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

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

סקווש

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

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

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

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

workbox-window מספק ממשק פשוט להאזנה למחזור החיים חשוב של Service Worker אירועים. מאחורי הקלעים, הספרייה משתמשת בממשקי API בצד הלקוח, כמו updatefound ושינוי מדינה ומספקת פונקציות 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 מספק דרך סטנדרטית להודיע ללקוחות החלונות על כך שתגובה שנשמרה במטמון עודכנה. הדבר הכי רווחיים יחד עם Stell timeRe Verification .

כדי לשדר עדכונים צריך להוסיף 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 להטמעת שידורי עדכונים:

ממשק API של ערוץ שידור

Service Worker יוצר 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, אבל לא כל השיטות שלו נתמכות. מומלץ לבדוק את התמיכה של הדפדפן לפני כן באמצעותו.

ערוץ הודעות

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

const messageChannel = new MessageChannel();

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

הדף מאזין להודעות על ידי הטמעת 'onmessage' ה-handler בשקע הזה:

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

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

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

השלבים הבאים

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

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

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

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