事前キャッシュなしでのワークボックスの使用

これまでこのドキュメントでは、プリキャッシュに重点を置き、generateSWinjectManifest のビルドツールについて説明してきました。サービス ワーカーにプリキャッシュ ロジックを組み込むには多くの理由がありますが、Workbox を使用するのにプリキャッシュを使用する必要はありません。

プロジェクトで必要なのがランタイム キャッシュのみである場合や、ウェブプッシュなど、サービス ワーカー API をよりクリーンな方法で統合したい場合もあります。このような場合は、Workbox のビルドツールを使用しないことをおすすめします。この記事では、そのようなケースについて説明します。

バンドルを使用する場合

バンドラはウェブ開発の分野でよく使用されており、プロジェクトで使用されている可能性が高いです。プリキャッシュを設定しない場合は、バンドル プラグイン(workbox-webpack-plugin など)を使用する必要はありません。サービス ワーカーは、アプリ内の別のエントリ ポイントとして扱います。

プロジェクトのソース ディレクトリのルートにサービス ワーカーを作成し、アプリケーションに必要な 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);

後は、このサービス ワーカーを、選択したバンドルツールのエントリポイントとして指定するだけです。以下に、一般的なバンドルツールでこれを行う方法の例を示します。

webpack

webpack は、entry 構成でエントリ ポイントを受け入れます。この方法を使用する際には、次の点に注意してください。

  1. Service Worker に可能な限り広いスコープを持たせるには、Service Worker を出力ディレクトリのルートに出力する必要があります。
  2. Service Worker にバージョンを付ける必要はありません。更新すると新しいハッシュが生成され、ウェブサイトに複数の Service Worker がデプロイされる可能性があります。

上記の条件を満たすには、関数を output.filename に渡して、処理中の現在のエントリ ポイントがサービス ワーカーのエントリ ポイントかどうかを確認します。それ以外の場合、バージョニングされたファイルは通常の宛先に書き込まれます。

// 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 を使用するバンドルツールなし

プロジェクトでバンドラを使用していない場合もあります。workbox-sw は、importScripts でインポートする場合、サービス ワーカー内の CDN から Workbox ランタイムをビルドステップなしで読み込むことができます。

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

CDN から Workbox ランタイムを読み込むのが難しい場合は、ローカル URL で workbox-sw を使用できます。

まとめ

プリキャッシュなしで Workbox を使用する方法を理解したので、特定のバンドルツールやビルドツールに縛られることがなくなりました。これにより、必要な Workbox のランタイム キャッシュ コードのみを使用して、Service Worker を手動で作成できます。