שימוש ביישומי פלאגין

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

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

יישומי פלאגין זמינים של Workbox

פלטפורמת Workbox מציעה את יישומי הפלאגין הרשמיים הבאים לשימוש ב-Service Worker:

יישומי פלאגין של תיבת עבודה — בין אם הם אחד מיישומי הפלאגין המפורטים למעלה או יישומי פלאגין מותאמים אישית — משמשים עם אסטרטגיית תיבת עבודה על ידי הוספת מופע של הפלאגין למאפיין plugins של האסטרטגיה:

import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';

registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      }),
    ],
  })
);

שיטות ליישומי פלאגין מותאמים אישית

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

  • cacheWillUpdate: מופעלת לפני שימוש ב-Response לעדכון מטמון. בשיטה הזו, ניתן לשנות את התגובה לפני שהיא מתווספת למטמון, או להחזיר null כדי להימנע מעדכון מלא של המטמון.
  • cacheDidUpdate: מתבצעת קריאה כאשר הוספה חדשה של רשומה חדשה למטמון או כאשר רשומה קיימת מתעדכנת. יישומי פלאגין שמשתמשים בשיטה הזו יכולים להיות שימושיים כשרוצים לבצע פעולה אחרי עדכון של המטמון.
  • cacheKeyWillBeUsed: השיחה מתקבלת לפני שבקשה משמשת כמפתח מטמון. הדבר נכון גם לחיפושי מטמון (כאשר mode הוא 'read') וגם לכתיבה מהמטמון (כאשר mode הוא 'write'). הקריאה החוזרת הזו שימושית אם צריך לשנות או לנרמל כתובות URL לפני שמשתמשים בהן כדי לגשת למטמון.
  • cachedResponseWillBeUsed: ההפעלה מתבצעת ממש לפני השימוש בתגובה ממטמון, כדי שתוכלו לבדוק את התשובה הזו. בשלב הזה, תוכל להחזיר תשובה אחרת או להחזיר null.
  • requestWillFetch: מתקבלת שיחה בכל פעם שבקשה עומדת לעבור לרשת. שימושי כאשר צריך לשנות את Request ממש לפני העברתו לרשת.
  • fetchDidFail: מופעלת כשבקשת רשת נכשלת, ככל הנראה עקב היעדר קישוריות לרשת, והיא לא מופעלת כשהדפדפן מחובר לרשת, אבל מקבל שגיאה (לדוגמה, 404 Not Found).
  • fetchDidSucceed: מופעלת כשבקשת רשת מצליחה, ללא קשר לקוד התגובה של ה-HTTP.
  • handlerWillStart: מופעלת לפני שלוגיקת handler מתחילה לפעול, והיא שימושית אם צריך להגדיר את המצב הראשוני של ה-handler. לדוגמה, אם אתם רוצים לדעת כמה זמן לקח ל-handler ליצור תגובה, תוכלו לרשום את שעת ההתחלה בקריאה החוזרת הזו.
  • handlerWillRespond: הקריאה הזו מופעלת לפני ששיטת handle() של השיטה מחזירה תשובה. האפשרות הזו מועילה אם אתם צריכים לשנות תשובה לפני החזרתה ל-RouteHandler או ללוגיקה מותאמת אישית אחרת.
  • handlerDidRespond: הקריאה מתבצעת אחרי השיטה handle() של השיטה, שמחזירה תשובה. במקרים כאלה כדאי לתעד את פרטי התגובה הסופית (לדוגמה, אחרי שינויים שבוצעו על ידי יישומי פלאגין אחרים).
  • handlerDidComplete: הוא נקרא אחרי שכל הבטחות לטווח הארוך נוספו לאירוע בעקבות הפעלת השיטה. התכונה הזו שימושית אם אתם צריכים לדווח על נתונים שצריכים להמתין עד שה-handler יסתיים כדי לחשב דברים כמו סטטוס ההתאמה של המטמון, זמן האחזור של המטמון, זמן האחזור של הרשת ומידע שימושי נוסף.
  • handlerDidError: התכונה הזו מופעלת אם ה-handler לא יכול לספק תשובה חוקית מאף מקור, וזה הזמן האופטימלי לספק תגובת גיבוי מסוג כלשהו כחלופה להיכשל.

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

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

const myPlugin = {
  cacheWillUpdate: async ({request, response, event, state}) => {
    // Return `response`, a different `Response` object, or `null`.
    return response;
  },
  cacheDidUpdate: async ({
    cacheName,
    request,
    oldResponse,
    newResponse,
    event,
    state,
  }) => {
    // No return expected
    // Note: `newResponse.bodyUsed` is `true` when this is called,
    // meaning the body has already been read. If you need access to
    // the body of the fresh response, use a technique like:
    // const freshResponse = await caches.match(request, {cacheName});
  },
  cacheKeyWillBeUsed: async ({request, mode, params, event, state}) => {
    // `request` is the `Request` object that would otherwise be used as the cache key.
    // `mode` is either 'read' or 'write'.
    // Return either a string, or a `Request` whose `url` property will be used as the cache key.
    // Returning the original `request` will make this a no-op.
    return request;
  },
  cachedResponseWillBeUsed: async ({
    cacheName,
    request,
    matchOptions,
    cachedResponse,
    event,
    state,
  }) => {
    // Return `cachedResponse`, a different `Response` object, or null.
    return cachedResponse;
  },
  requestWillFetch: async ({request, event, state}) => {
    // Return `request` or a different `Request` object.
    return request;
  },
  fetchDidFail: async ({originalRequest, request, error, event, state}) => {
    // No return expected.
    // Note: `originalRequest` is the browser's request, `request` is the
    // request after being passed through plugins with
    // `requestWillFetch` callbacks, and `error` is the exception that caused
    // the underlying `fetch()` to fail.
  },
  fetchDidSucceed: async ({request, response, event, state}) => {
    // Return `response` to use the network response as-is,
    // or alternatively create and return a new `Response` object.
    return response;
  },
  handlerWillStart: async ({request, event, state}) => {
    // No return expected.
    // Can set initial handler state here.
  },
  handlerWillRespond: async ({request, response, event, state}) => {
    // Return `response` or a different `Response` object.
    return response;
  },
  handlerDidRespond: async ({request, response, event, state}) => {
    // No return expected.
    // Can record final response details here.
  },
  handlerDidComplete: async ({request, response, error, event, state}) => {
    // No return expected.
    // Can report any data here.
  },
  handlerDidError: async ({request, event, error, state}) => {
    // Return a `Response` to use as a fallback, or `null`.
    return fallbackResponse;
  },
};

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

לכל הקריאות החוזרות של הפלאגין מועברים גם אובייקט state, שהוא ייחודי לפלאגין מסוים ולאסטרטגיה שהוא מפעיל. כלומר, אתם יכולים לכתוב יישומי פלאגין שבהם קריאה חוזרת אחת יכולה לבצע משימה באופן מותנה, על סמך הפעולה שעשתה קריאה חוזרת אחרת באותו פלאגין (לדוגמה, חישוב ההבדל בין הפעלת requestWillFetch() לבין fetchDidSucceed() או fetchDidFail()).

יישומי פלאגין של צד שלישי

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

ייתכן שתוכל למצוא יישומי פלאגין נוספים של Workbox בקהילה באמצעות חיפוש במאגר של npm.

לסיום, אם בנית פלאגין של Workbox שברצונך לשתף, הוסף את מילת המפתח workbox-plugin כאשר תפרסם אותו. אם כן, נשמח לדעת ב-Twitter @WorkboxJS!