フォールバック レスポンスの管理

特定の状況では、ユーザーがオフラインの場合に備えて、フォールバック レスポンスをキャッシュしたいことがあります。フォールバックの実装は、ネットワーク ファーストや Stale-while-revalidate などの戦略によるキャッシュ動作の代替となります。

フォールバックは汎用的な汎用レスポンスで、リクエストが失敗した場合にブラウザがデフォルトで提供するものよりも優れたプレースホルダです。以下にいくつか例を示します。

  • 「画像がありません」の代わり使用します。
  • 標準的な「ネットワーク接続を利用できません」に代わる HTML 方法できます。

オフライン ページのみ

カスタムのオフライン HTML ページを用意するだけで、それ以外は必要ないという場合は、次の基本的なレシピに沿って操作してください。

import {offlineFallback} from 'workbox-recipes';
import {setDefaultHandler} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

setDefaultHandler(new NetworkOnly());

offlineFallback();

上記のコードでは、setDefaultHandler を使用して、ネットワークのみの戦略をすべてのルートのデフォルトとして使用します。次に offlineFallback レシピを実行して、エラーが発生した場合にオフライン フォールバックを提供します。このレシピでは、オフラインの代替 HTML ファイルの名前は offline.html で、ウェブサーバーのルートから提供されることを前提としています。

包括的なフォールバック

ネットワーク障害やキャッシュミスが発生した場合、workbox-strategies が提供するキャッシュ戦略は常に拒否されます。これにより、グローバルな「キャッチ」を設定するパターンが1 つのハンドラ関数ですべてのエラーを処理できます。これにより、request.destination 値ごとに異なるフォールバックを提供できます。

次の例では、workbox-recipeswarmStrategyCache レシピを使用して、ランタイム キャッシュに事前にキャッシュされたアイテムを提供するキャッチ ハンドラを設定しています。ただし、アプリケーションには、フォールバックの事前キャッシュが適している場合があります。

import {warmStrategyCache} from 'workbox-recipes';
import {setDefaultHandler, setCatchHandler} from 'workbox-routing';
import {CacheFirst, StaleWhileRevalidate} from 'workbox-strategies';

// Fallback assets to cache
const FALLBACK_HTML_URL = '/offline.html';
const FALLBACK_IMAGE_URL = '/images/image-not-found.jpg';
const FALLBACK_STRATEGY = new CacheFirst();

// Warm the runtime cache with a list of asset URLs
warmStrategyCache({
  urls: [FALLBACK_HTML_URL, FALLBACK_IMAGE_URL],
  strategy: FALLBACK_STRATEGY,
});

// Use a stale-while-revalidate strategy to handle requests by default.
setDefaultHandler(new StaleWhileRevalidate());

// This "catch" handler is triggered when any of the other routes fail to
// generate a response.
setCatchHandler(async ({request}) => {
  // The warmStrategyCache recipe is used to add the fallback assets ahead of
  // time to the runtime cache, and are served in the event of an error below.
  // Use `event`, `request`, and `url` to figure out how to respond, or
  // use request.destination to match requests for specific resource types.
  switch (request.destination) {
    case 'document':
      return FALLBACK_STRATEGY.handle({event, request: FALLBACK_HTML_URL});

    case 'image':
      return FALLBACK_STRATEGY.handle({event, request: FALLBACK_IMAGE_URL});

    default:
      // If we don't have a fallback, return an error response.
      return Response.error();
  }
});

次に、Workbox のビルドツールで injectManifest を使用してフォールバック レスポンスを事前キャッシュに保存し、matchPrecache メソッドでエラーが発生した場合のフォールバックとして機能します。

import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {setDefaultHandler, setCatchHandler} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';

// Optional: use the injectManifest mode of one of the Workbox
// build tools to precache a list of URLs, including fallbacks.
precacheAndRoute(self.__WB_MANIFEST);

// Use a stale-while-revalidate strategy to handle requests by default.
setDefaultHandler(new StaleWhileRevalidate());

// This "catch" handler is triggered when any of the other routes fail to
// generate a response.
setCatchHandler(async ({request}) => {
  // Fallback assets are precached when the service worker is installed, and are
  // served in the event of an error below. Use `event`, `request`, and `url` to
  // figure out how to respond, or use request.destination to match requests for
  // specific resource types.
  switch (request.destination) {
    case 'document':
      // FALLBACK_HTML_URL must be defined as a precached URL for this to work:
      return matchPrecache(FALLBACK_HTML_URL);

    case 'image':
      // FALLBACK_IMAGE_URL must be defined as a precached URL for this to work:
      return matchPrecache(FALLBACK_IMAGE_URL);

    default:
      // If we don't have a fallback, return an error response.
      return Response.error();
  }
});

2 つ目の代替設定のユースケースの例として、ページは事前にキャッシュに保存されたものの、ページでリクエストされた画像(または他のアセット)はキャッシュに保存されなかった場合が挙げられます。ユーザーがオフラインのときでもキャッシュからページを読み取ることはできますが、ネットワーク エラーが発生した場合は代替のプレースホルダや代替機能を提供できます。

ランタイム キャッシュのウォームアップ

Workbox は、プレキャッシュ用とランタイム キャッシュ用に別々のキャッシュを保持します。また、プリキャッシュ マニフェストの更新には更新された Service Worker をデプロイする必要があるため、プレキャッシュに依存せずに事前に何かをキャッシュしたい状況も考えられます。

アセットでランタイム キャッシュを事前に準備するには、workbox-recipeswarmStrategyCache レシピを使用します。この戦略は、内部で Service Worker の install イベントで Cache.addAll を呼び出します。

import {warmStrategyCache} from 'workbox-recipes';
import {CacheFirst} from 'workbox-strategies';

// This can be any strategy, CacheFirst used as an example.
const strategy = new CacheFirst();
const urls = [
  '/offline.html',
];

warmStrategyCache({urls, strategy});

まとめ

失敗したリクエストに対するフォールバック レスポンスの管理には多少の手間がかかりますが、事前に計画を立てておくことで、ユーザーがオフラインのときでもある程度のコンテンツや機能を提供できるようにウェブアプリを設定できます。