יצירת חוויות חיפוש עמידות באמצעות תיבת עבודה

בשיעור הזה תלמדו איך להטמיע חוויית חיפוש עמידה עם Workbox. אפליקציית ההדגמה שבה נעשה שימוש מכילה תיבת חיפוש שקוראת לנקודת קצה (endpoint) של שרת ומפנה את המשתמש לדף HTML בסיסי.

מדידה

לפני הוספת אופטימיזציות, תמיד כדאי לנתח תחילה את המצב הנוכחי של האפליקציה.

  • לוחצים על רמיקס לעריכה כדי שיהיה אפשר לערוך את הפרויקט.
  • כדי לראות תצוגה מקדימה של האתר, מקישים על View App ואז על Fullscreen מסך מלא.

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

  1. לוחצים על 'Control+Shift+J' (או 'Command+Option+J' ב-Mac) כדי לפתוח את כלי הפיתוח.
  2. לוחצים על הכרטיסייה רשתות.
  3. פותחים את כלי הפיתוח ל-Chrome ובוחרים בחלונית 'רשת'.
  4. ברשימה הנפתחת של ויסות נתונים, בוחרים באפשרות אופליין.
  5. באפליקציית ההדגמה, מזינים שאילתת חיפוש ולאחר מכן לוחצים על הלחצן חיפוש.

מוצג דף השגיאה הרגיל של הדפדפן:

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

צריך לספק תשובה חלופית

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

בדרך כלל, צריך להנחות את Workbox להוסיף את הקובץ הזה לרשימת המטמון בזמן ה-build על ידי שילוב הספרייה עם כלי ה-build שבחרתם (למשל, webpack או gulp).

לשם הפשטות, כבר עשינו את זה בשבילך. הקוד הבא ב-public/sw.js מבצע את הפעולה הזו:

const FALLBACK_HTML_URL = '/index_offline.html';
…
workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);

בשלב הבא, מוסיפים קוד שישמש בדף אופליין כתגובה חלופית:

  1. כדי להציג את המקור, לוחצים על הצגת מקור.
  2. מוסיפים את הקוד הבא בחלק התחתון של public/sw.js:
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());

workbox.routing.setCatchHandler(({event}) => {
  switch (event.request.destination) {
    case 'document':
      return caches.match(FALLBACK_HTML_URL);
      break;
    default:
      return Response.error();
  }
});

הקוד מבצע את הפעולות הבאות:

  • מגדיר ברירת מחדל לאסטרטגיית רשת בלבד שתחול על כל הבקשות.
  • מצהירה על handler של שגיאות גלובליות, באמצעות קריאה ל-workbox.routing.setCatchHandler() כדי לנהל את הבקשות שנכשלו. כשהבקשות מיועדות למסמכים, מוחזר דף HTML חלופי לא מקוון.

כדי לבדוק את הפונקציונליות הזו:

  1. חוזרים לכרטיסייה האחרת שמפעילה את האפליקציה.
  2. החזר את הרשימה הנפתחת ויסות נתונים לאונליין.
  3. לוחצים על הלחצן הקודם ב-Chrome כדי לנווט חזרה לדף החיפוש.
  4. מוודאים שתיבת הסימון השבתת המטמון בכלי הפיתוח מושבתת.
  5. לוחצים לחיצה ארוכה על הלחצן Reload ב-Chrome ובוחרים באפשרות ריקון המטמון וטעינה קשיחה מחדש כדי לוודא שה-Service Worker מעודכן.
  6. מחזירים את הרשימה הנפתחת ויסות נתונים למצב אופליין.
  7. מזינים שאילתת חיפוש ולוחצים שוב על הלחצן חיפוש.

מוצג דף ה-HTML החלופי:

צילום מסך של חוויית המשתמש אופליין בהתאמה אישית בדפדפן.

שליחת בקשה להרשאה לשליחת התראות

כדי לשמור על הפשטות, הדף אופליין בכתובת views/index_offline.html כבר מכיל את הקוד לבקשת הרשאות להתראות, בבלוק סקריפט בחלק התחתון:

function requestNotificationPermission(event) {
  event.preventDefault();

  Notification.requestPermission().then(function (result) {
    showOfflineText(result);
  });
}

הקוד מבצע את הפעולות הבאות:

  • כשהמשתמש לוחץ על הרשמה לקבלת התראות, הפונקציה requestNotificationPermission() נקראת, וקוראת ל-Notification.requestPermission(), כדי להציג את בקשת ההרשאה של הדפדפן שמוגדרת כברירת מחדל. ההבטחה מסתיימת עם ההרשאה שבחר המשתמש, שיכולה להיות granted, denied או default.
  • מעביר את ההרשאה שטופלה אל showOfflineText() כדי להציג את הטקסט המתאים למשתמש.

שמירת שאילתות אופליין וניסיון נוסף כשיהיה שוב חיבור לאינטרנט

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

  1. אפשר לפתוח את public/sw.js כדי לערוך.
  2. מוסיפים את הקוד הבא בסוף הקובץ:
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
  maxRetentionTime: 60,
  onSync: async ({queue}) => {
    let entry;
    while ((entry = await queue.shiftRequest())) {
      try {
        const response = await fetch(entry.request);
        const cache = await caches.open('offline-search-responses');
        const offlineUrl = `${entry.request.url}&notification=true`;
        cache.put(offlineUrl, response);
        showNotification(offlineUrl);
      } catch (error) {
        await this.unshiftRequest(entry);
        throw error;
      }
    }
  },
});

הקוד מבצע את הפעולות הבאות:

  • workbox.backgroundSync.Plugin כולל את הלוגיקה להוסיף לתור בקשות שנכשלו, כך שיהיה אפשר לנסות שוב מאוחר יותר. הבקשות האלה יישמרו ב-IndexedDB.
  • maxRetentionTime מציין את משך הזמן שבו ניתן לנסות שוב לשלוח בקשה. במקרה הזה בחרנו ב-60 דקות (ולאחר מכן הן תיעלם).
  • onSync הוא החלק החשוב ביותר בקוד הזה. הקריאה החוזרת הזו תתבצע כשהחיבור יחודש, כדי שהבקשות שבתור יאוחזרו ולאחר מכן יאוחזרו מהרשת.
  • תגובת הרשת מתווספת למטמון offline-search-responses ומוסיפה את פרמטר השאילתה &notification=true, כדי שניתן יהיה לקלוט את רשומת המטמון הזו כשמשתמש לוחץ על ההתראה.

כדי לשלב סנכרון ברקע עם השירות שלכם, צריך להגדיר אסטרטגיית NetworkOnly לבקשות אל כתובת ה-URL של החיפוש (/search_action) ולהעביר את bgSyncPlugin שהוגדר קודם לכן. מוסיפים את הקוד הבא בחלק התחתון של public/sw.js:

const matchSearchUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return url.pathname === '/search_action' && !(notificationParam === 'true');
};

workbox.routing.registerRoute(
  matchSearchUrl,
  new workbox.strategies.NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
);

פעולה זו מורה ל-Workbox לעבור תמיד לרשת, וכאשר בקשות נכשלות, להשתמש בלוגיקת הסנכרון ברקע.

בשלב הבא צריך להוסיף את הקוד הבא לחלק התחתון של public/sw.js כדי להגדיר אסטרטגיית שמירה במטמון לבקשות שמגיעות מהתראות. משתמשים באסטרטגיה CacheFirst, כדי שניתן יהיה להציג אותן מהמטמון.

const matchNotificationUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return (url.pathname === '/search_action' && (notificationParam === 'true'));
};

workbox.routing.registerRoute(matchNotificationUrl,
  new workbox.strategies.CacheFirst({
     cacheName: 'offline-search-responses',
  })
);

לסיום, מוסיפים את הקוד כדי להציג התראות:

function showNotification(notificationUrl) {
  if (Notification.permission) {
     self.registration.showNotification('Your search is ready!', {
        body: 'Click to see you search result',
        icon: '/img/workbox.jpg',
        data: {
           url: notificationUrl
        }
     });
  }
}

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
     clients.openWindow(event.notification.data.url)
  );
});

בדיקת התכונה

  1. חוזרים לכרטיסייה האחרת שמפעילה את האפליקציה.
  2. החזר את הרשימה הנפתחת ויסות נתונים לאונליין.
  3. לוחצים על הלחצן הקודם ב-Chrome כדי לנווט חזרה לדף החיפוש.
  4. לוחצים לחיצה ארוכה על הלחצן Reload ב-Chrome ובוחרים באפשרות ריקון המטמון וטעינה קשיחה מחדש כדי לוודא שה-Service Worker מעודכן.
  5. מחזירים את הרשימה הנפתחת ויסות נתונים למצב אופליין.
  6. מזינים שאילתת חיפוש ולוחצים שוב על הלחצן חיפוש.
  7. לוחצים על הרשמה לקבלת התראות.
  8. כש-Chrome שואל אם להעניק לאפליקציה הרשאה לשלוח התראות, לוחצים על Allow.
  9. מזינים שאילתת חיפוש נוספת ולוחצים שוב על הלחצן חיפוש.
  10. החזר את הרשימה הנפתחת throttling בחזרה ל-Online (אונליין).

כשהחיבור יחודש, תוצג התראה:

צילום מסך של התהליך המלא במצב אופליין.

סיכום

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