Utiliser Workbox sans la mise en cache préalable

Jusqu'à présent, cette documentation a beaucoup insisté sur le précaching, en abordant souvent les outils de compilation generateSW et injectManifest. Bien qu'il existe de nombreuses bonnes raisons d'inclure une logique de préchargement dans votre service worker, vous n'êtes pas obligé d'utiliser le préchargement pour utiliser Workbox.

Votre projet n'a peut-être besoin que de la mise en cache d'exécution, ou vous souhaitez peut-être intégrer plus facilement des API de service worker, comme le push Web. Dans certains cas, vous ne souhaitez pas utiliser les outils de compilation de Workbox. C'est ce que nous allons voir dans cet article.

Lorsque vous utilisez un bundler

Les bundleurs sont très présents dans le paysage du développement Web, et il est probable que votre projet en utilise un. Dans ce cas, sachez qu'il n'est pas nécessaire d'utiliser un plug-in de regroupement (comme workbox-webpack-plugin) si vous ne précachez rien. Vous allez traiter votre service worker comme un point d'entrée distinct dans votre application.

Dans le répertoire source racine de votre projet, vous allez créer un service worker et utiliser les modules Workbox dont votre application a besoin. Voici un exemple sans préchargement, qui configure des stratégies de mise en cache pour les requêtes de navigation et d'éléments d'image dans des instances Cache distinctes:

// 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);

À partir de là, il s'agit de spécifier ce service worker comme point d'entrée dans le bundler de votre choix. Vous trouverez ci-dessous quelques exemples de la façon dont vous pouvez procéder dans quelques outils de compilation populaires.

webpack

webpack accepte les points d'entrée dans sa configuration entry. Voici quelques points à prendre en compte lorsque vous utilisez cette approche:

  1. Pour vous assurer que votre service worker a la portée la plus large possible, vous devez le générer à la racine de votre répertoire de sortie.
  2. Vous ne souhaitez pas que le service worker soit versionné, car ses mises à jour génèrent de nouveaux hachages qui peuvent entraîner le déploiement de plusieurs service workers sur votre site Web.

Pour répondre aux conditions ci-dessus, une fonction peut être transmise à output.filename, qui examine si le point d'entrée actuel en cours de traitement est le point d'entrée du service worker. Sinon, les fichiers versionnés sont écrits dans leurs destinations normales.

// 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
  }
};

agrégation

La situation du groupement est semblable à celle de webpack, à la différence que plusieurs points d'entrée sont spécifiés en tant qu'objets de configuration distincts exportés dans un tableau:

// 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 propose une interface de ligne de commande simple:

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

esbuild se chargera de remplacer process.env.NODE_ENV par "development" par défaut, ou "production" si la minification est activée.

Sans bundler à l'aide de workbox-sw

Il est possible que votre projet n'utilise même pas de bundler. workbox-sw peut charger l'environnement d'exécution Workbox à partir d'un CDN dans votre service worker et sans étape de compilation si vous l'importez avec importScripts:

// 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);

Si le chargement de l'environnement d'exécution Workbox depuis un CDN ne vous semble pas idéal, vous pouvez utiliser workbox-sw avec des URL locales.

Conclusion

Maintenant que vous savez utiliser Workbox sans préchargement, vous n'êtes plus lié à un outil de compilation ou de regroupement particulier. Vous avez ainsi la possibilité de créer manuellement un service worker en n'utilisant que les bits du code de mise en cache de l'environnement d'exécution de Workbox qui vous intéressent.