שמירת משאבים במטמון במהלך זמן ריצה

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

ב-Workbox, אפשר לטפל בשמירה במטמון של זמן ריצה עבור נכסים באמצעות המודול workbox-routing כדי להתאים מסלולים, ולטפל באסטרטגיות שמירה במטמון עבורם באמצעות המודול workbox-strategies.

אסטרטגיות של שמירה במטמון

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

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

אפשר להחיל את האסטרטגיות האלה על בקשות נבחרות באמצעות שיטות שמוצעות על ידי workbox-routing.

החלה של אסטרטגיות שמירה במטמון עם התאמה למסלולים

workbox-routing חושפת method registerRoute כדי להתאים מסלולים ולטפל בהם באמצעות אסטרטגיית שמירה במטמון. registerRoute מקבל אובייקט Route שמקבל שני ארגומנטים:

  1. מחרוזת, ביטוי רגולרי או קריאה חוזרת (callback) של התאמה כדי לציין קריטריונים של התאמת מסלול.
  2. רכיב handler של המסלול – בדרך כלל אסטרטגיה שמסופקת על ידי workbox-strategies.

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

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

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';

// A new route that matches same-origin image requests and handles
// them with the cache-first, falling back to network strategy:
const imageRoute = new Route(({ request, sameOrigin }) => {
  return sameOrigin && request.destination === 'image'
}, new CacheFirst());

// Register the new route
registerRoute(imageRoute);

שימוש בכמה מטמון

תיבת העבודה מאפשרת לקבץ תגובות שנשמרו במטמון למכונות Cache נפרדות באמצעות האפשרות cacheName שזמינה באסטרטגיות המקובצות.

בדוגמה הבאה, התמונות משתמשות באסטרטגיה של אימות לא פעיל בזמן אימות מחדש, ואילו נכסי CSS ו-JavaScript משתמשים באסטרטגיית רשת לשמירה במטמון. המסלול של כל נכס שומר את התגובות במטמון נפרד על ידי הוספת המאפיין cacheName.

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies';

// Handle images:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image'
}, new StaleWhileRevalidate({
  cacheName: 'images'
}));

// Handle scripts:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts'
}));

// Handle styles:
const stylesRoute = new Route(({ request }) => {
  return request.destination === 'style';
}, new CacheFirst({
  cacheName: 'styles'
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);
registerRoute(stylesRoute);
צילום מסך של רשימת מופעים של המטמון בכרטיסייה של האפליקציה בכלי הפיתוח ב-Chrome. מוצגים שלושה קבצים שמורים נפרדים: אחד בשם 'סקריפטים', אחד בשם 'סגנונות' והאחרון הוא 'תמונות'.
התצוגה של 'אחסון המטמון' בחלונית האפליקציות של כלי הפיתוח ל-Chrome. התגובות לסוגי נכסים שונים מאוחסנות במטמון נפרד.

הגדרת תפוגה לרשומות של מטמון

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

// sw.js
import { registerRoute, Route } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

// Evict image cache entries older thirty days:
const imageRoute = new Route(({ request }) => {
  return request.destination === 'image';
}, new CacheFirst({
  cacheName: 'images',
  plugins: [
    new ExpirationPlugin({
      maxAgeSeconds: 60 * 60 * 24 * 30,
    })
  ]
}));

// Evict the least-used script cache entries when
// the cache has more than 50 entries:
const scriptsRoute = new Route(({ request }) => {
  return request.destination === 'script';
}, new CacheFirst({
  cacheName: 'scripts',
  plugins: [
    new ExpirationPlugin({
      maxEntries: 50,
    })
  ]
}));

// Register routes
registerRoute(imageRoute);
registerRoute(scriptsRoute);

עמידה במכסות האחסון יכולה להיות לא פשוטה. מומלץ לחשוב על משתמשים שיש להם לחץ על נפח האחסון או שהם רוצים לנצל את נפח האחסון שלהם בצורה היעילה ביותר. צמדים של ExpirationPlugin ב-Workbox יכולים לעזור להשיג את היעד הזה.

שיקולים לגבי מקורות שונים

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

תשובות אטומות

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

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

זכרו להצטרף למצב CORS

גם אם טוענים נכסים ממקורות שונים שכן הגדירו כותרות CORS מתירניות שמאפשרות לקרוא תשובות, גוף התגובה ממקורות שונים עדיין עשוי להיות אטום. לדוגמה, קוד ה-HTML הבא יפעיל בקשות no-cors שיובילו לתגובות אטומות ללא קשר לכותרות ה-CORS שמוגדרות:

<link rel="stylesheet" href="https://example.com/path/to/style.css">
<img src="https://example.com/path/to/image.png">

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

<link crossorigin="anonymous" rel="stylesheet" href="https://example.com/path/to/style.css">
<img crossorigin="anonymous" src="https://example.com/path/to/image.png">

חשוב לזכור כשמסלולים במשאבי המשנה של קובץ השירות (service worker) נטענים בזמן הריצה.

תיבת העבודה לא יכולה לשמור תגובות אטומות

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

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

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

אילוץ שמירה של תגובות אטומות במטמון

אם אתם בטוחים לחלוטין שרוצים לשמור תגובה אטומה במטמון באמצעות אסטרטגיה שמתמקדת במטמון או במטמון בלבד, אפשר לאלץ את סביבת העבודה לעשות זאת באמצעות המודול workbox-cacheable-response:

import {Route, registerRoute} from 'workbox-routing';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {CacheableResponsePlugin} from 'workbox-cacheable-response';

const cdnRoute = new Route(({url}) => {
  return url === 'https://cdn.google.com/example-script.min.js';
}, new CacheFirst({
  plugins: [
    new CacheableResponsePlugin({
      statuses: [0, 200]
    })
  ]
}))

registerRoute(cdnRoute);

תשובות אטומות ו-API של navigator.storage

כדי למנוע דליפת מידע בכמה דומיינים, יש מרווח פנימי משמעותי לגודל של תגובה אטומה שמשמשת לחישוב המגבלות של מכסת האחסון. השינוי הזה משפיע על האופן שבו מכסות האחסון מדווחים ב-API של navigator.storage.

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