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

עד כה, המסמך הזה התמקד בעיקר בשמירת פריטים במטמון מראש, והתייחס לעיתים קרובות לכלים ל-build של generateSW ו-injectManifest. יש הרבה סיבות טובות לכלול לוגיקה של אחסון מראש בקובץ ה-service worker, אבל אין צורך להשתמש באחסון מראש כדי להשתמש ב-Workbox.

יכול להיות שבפרויקט שלכם יש צורך רק בשמירת נתונים במטמון בסביבת זמן הריצה, או שאתם רוצים דרך נקייה יותר לשילוב ממשקי API של קובצי שירות, כמו web push. במקרים כאלה, לא כדאי להשתמש בכלי ה-build של Workbox, וזה מה שמוסבר במאמר הזה.

כשמשתמשים ב-bundler

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

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

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

const navigationRoute = new NavigationRoute(new NetworkFirst({
  cacheName: 'navigations'
}));

const imageAssetRoute = new Route(({request}) => {
  return request.destination === 'image';
}, new CacheFirst({
  cacheName: 'image-assets'
}));

registerRoute(navigationRoute);
registerRoute(imageAssetRoute);

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

webpack

webpack מקבל נקודות כניסה בהגדרת entry שלו. יש כמה דברים שכדאי לדעת כשמשתמשים בגישה הזו:

  1. כדי להבטיח שה-Service Worker יחזיק בהיקף רחב ככל האפשר, צריך לבחור אותו כפלט שברמה הבסיסית (root) של ספריית הפלט.
  2. לא כדאי ליצור גרסאות של ה-service worker, כי עדכונים שלו ייצרו גרסאות גיבוב חדשות שעשויות לגרום לפריסה של כמה service workers באתר.

כדי לעמוד בתנאים שלמעלה, אפשר להעביר פונקציה אל output.filename, שתבדוק אם נקודת הכניסה הנוכחית שמעובדת היא נקודת הכניסה של ה-service worker. אחרת, קבצים עם גרסאות נכתבים ליעדים הרגילים שלהם.

// webpack.config.js
import process from 'process';

const isProd = process.env.NODE_ENV === 'production';

export default {
  mode: isProd ? 'production' : 'development',
  context: process.cwd(),
  entry: {
    // Service worker entry point:
    sw: './src/sw.js',
    // Application entry point:
    app: './src/index.js'
  },
  output: {
    filename: ({runtime}) => {
      // Check if the current filename is for the service worker:
      if (runtime === 'sw') {
        // Output a service worker in the root of the dist directory
        // Also, ensure the output file name doesn't have a hash in it
        return '[name].js';
      }

      // Otherwise, output files as normal
      return 'js/[name].[contenthash:8].js';
    },
    path: './dist',
    publicPath: '/',
    clean: true
  }
};

נכס-על

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

// rollup.config.js
import { nodeResolve } from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';

// Plugins common to both entry points
const plugins = [
  nodeResolve(),
];

export default [
  // Application entry point
  {
    input: './src/index.js',
    output: {
      dir: './dist/js',
      format: 'esm'
    },
    plugins
  },
  // Service worker entry point
  {
    input: './src/sw.js',
    output: {
      file: './dist/sw.js',
      format: 'iife'
    },
    plugins: [
      ...plugins,
      // This @rollup/plugin-replace instance replaces process.env.NODE_ENV
      // statements in the Workbox libraries to match your current environment.
      // This changes whether logging is enabled ('development') or disabled ('production').
      replace({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
      })
    ]
  }
];

esbuild

esbuild מציע ממשק שורת פקודה פשוט:

npx esbuild ./src/sw.js --bundle --minify --outfile=./dist/sw.js

‏esbuild ידאג להחליף את process.env.NODE_ENV ב-'development' כברירת מחדל, או ב-'production' אם אופטימיזציה לחיסכון במקום מופעלת.

בלי חבילה באמצעות workbox-sw

יכול להיות שהפרויקט שלכם לא משתמש בכלל ב-bundler. אפשר לייבא את workbox-sw באמצעות importScripts כדי לטעון את סביבת זמן הריצה של Workbox מ-CDN בתוך ה-service worker, בלי שלב build:

// sw.js

// Imports Workbox from the CDN. Note that "6.2.0" of the URL
// is the version of the Workbox runtime.
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.2.0/workbox-sw.js');

const navigationRoute = new workbox.routing.NavigationRoute(new workbox.strategies.NetworkFirst({
  cacheName: 'navigations'
}));

const imageAssetRoute = new workbox.routing.Route(({request}) => {
  return request.destination === 'image';
}, new workbox.strategies.CacheFirst({
  cacheName: 'image-assets'
}));

workbox.routing.registerRoute(navigationRoute);
workbox.routing.registerRoute(staticAssetRoute);

אם אתם לא רוצים לטעון את סביבת זמן הריצה של Workbox מ-CDN, תוכלו להשתמש ב-workbox-sw עם כתובות URL מקומיות.

סיכום

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