ネットワーク ファーストの HTML のナビゲーション プリロード

Service Worker が fetch イベントを処理すると、ブラウザは Service Worker からの応答を待機します。ネットワーク リクエストのレイテンシは待ち時間の大半を占めますが、ブラウザは Service Worker が起動して fetch イベント コールバックをトリガーするまで待機しなければならない場合もあります。

起動時間はデバイスやその機能によって異なりますが、かなりの時間がかかることがあり、CPU の動作が遅い場合や周囲条件によりスロットリング状態になっている場合は 0.5 秒ほどになることもあります。ナビゲーション レスポンスが Cache インスタンスから提供される場合、ネットワークを回避することでパフォーマンスが向上する可能性があります。ネットワークに送信されるナビゲーション リクエストの場合、Service Worker を導入すると、目に見える遅延が生じる可能性があります。

ナビゲーションのプリロードを開始

ナビゲーションのプリロードは、Service Worker の起動時間に起因する遅延を解決する Service Worker の機能です。ナビゲーションのプリロードが有効になっていないと、Service Worker の起動と Service Worker が処理するナビゲーション リクエストの両方が連続して行われます。

連続するアクションを示す 2 つのセグメントがある、黄色と青色のバー。黄色で表示された最初のセグメントには「SW boot」と書かれています。青いセグメントが「ナビゲーションリクエスト」と
書かれています

これは理想的ではありませんが、ナビゲーションのプリロードを有効にすることで修正できます。これにより、Service Worker の起動とナビゲーション リクエストが同時に発生します。

2 つのバーが積み重ねられ、左揃えで並んでいます。2 つの同時アクションを表しています。黄色のバーには「SW ブート」、青色のバーには「ナビゲーション リクエスト」というラベルが付いています。

ナビゲーションのプリロードは、Service Worker を使用するサイトのパフォーマンス最適化に優れていますが、すべての状況で有効にすべき機能ではありません。特に、事前キャッシュされた App Shell を使用するサイトでは、ナビゲーションのプリロードは必要ありません。キャッシュは、App Shell マークアップのナビゲーション リクエストをナビゲーション レイテンシなしで処理するためです。このようなケースでは、プリロードされたレスポンスが無駄になってしまいます。

ナビゲーションのプリロードは、ウェブサイトで HTML の事前キャッシュができない場合に最適です。マークアップのレスポンスが動的で、認証状態などによって変化するウェブサイトを考えてみてください。これらのナビゲーション リクエストでは、ネットワーク優先(またはネットワークのみ)の戦略が使用される場合があります。その場合は、ナビゲーションのプリロードが大きな違いを生みます。

Workbox でのナビゲーションのプリロードの使用

Workbox を利用していない Service Worker でナビゲーション プリロードを直接使用するのは、簡単ではありません。まず、サポートされないブラウザもあります。第二に、正しく行うことが難しい場合があります。使用方法については、Jake Archibald によるこちらの解説をご覧ください。

Workbox は、ナビゲーションのプリロードの使用を簡素化します。これは、workbox-navigation-preload モジュールの enable メソッドが、必要な機能サポートのチェックを行い、activate イベント リスナーを作成して有効化するためです。

ここからは、ブラウザをサポートする際に、ワークボックスを使用してネットワーク ファーストの戦略ハンドラでナビゲーション リクエストを処理することで、ナビゲーションのプリロードのメリットが実現します。

import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {registerRoute, NavigationRoute, Route} from 'workbox-routing';
import {precacheAndRoute} from 'workbox-precaching';

// Precache the manifest
precacheAndRoute(self.__WB_MANIFEST);

// Enable navigation preload
navigationPreload.enable();

// Create a new navigation route that uses the Network-first, falling back to
// cache strategy for navigation requests with its own cache. This route will be
// handled by navigation preload. The NetworkOnly strategy will work as well.
const navigationRoute = new NavigationRoute(new NetworkFirst({
  cacheName: 'navigations'
}));

// Register the navigation route
registerRoute(navigationRoute);

// Create a route for image, script, or style requests that use a
// stale-while-revalidate strategy. This route will be unaffected
// by navigation preload.
const staticAssetsRoute = new Route(({request}) => {
  return ['image', 'script', 'style'].includes(request.destination);
}, new StaleWhileRevalidate({
  cacheName: 'static-assets'
}));

// Register the route handling static assets
registerRoute(staticAssetsRoute);

ナビゲーションのプリロードが有効になっている場合、Workbox は NetworkFirst または NetworkOnly 戦略を使用するナビゲーション リクエストに、プリロードされたレスポンスで応答します。

ナビゲーションのプリロードが機能しているかどうかを確認するにはどうすればよいですか?

開発ビルドでは、Workbox が何を行うかについて大量のログが記録されます。Workbox でナビゲーションのプリロードが機能しているかどうかを確認するには、ナビゲーション リクエスト中に対応ブラウザでコンソールを開くと、次のようなログメッセージが表示されます。

Chrome の DevTools のコンソールに表示された Workbox のログのスクリーンショット。メッセージは上から順に、「ルーターが / に応答しています」、「プリロードされたナビゲーション リクエストを / に使用している」、「NetworkFirst を使用して / に応答しています」という内容のメッセージが表示されます。

このロギングは、デフォルトでは本番環境のビルドでは表示されないため、Service Worker を本番環境にデプロイするときには表示されませんが、ナビゲーション プリロードが(とりわけ)機能していることを確認できる優れた方法です。

プリロード レスポンスのカスタマイズ

ナビゲーションのプリロードを使用する場合、アプリのバックエンドでプリロードされたレスポンスのカスタマイズが必要になることがあります。Service Worker でネットワークから部分的なコンテンツをストリーミングする場合、これが便利なシナリオの 1 つです。

このような場合、Service-Worker-Navigation-Preload ヘッダーがデフォルト値の true に設定された状態でプリロード リクエストが送信されていることを把握しておくと役に立ちます。

Service-Worker-Navigation-Preload: true

次に、使用するアプリケーション バックエンドでこのヘッダーを確認し、必要に応じてレスポンスを変更できます。なんらかの理由でヘッダーのデフォルト値に問題がある場合は、ウィンドウ コンテキストで変更できます。このヘッダーを読み取るためにサーバーで行う作業はあなた次第であり、Workbox の対象範囲外となります。

まとめ

直接使用するとナビゲーションのプリロードを正しく行うことは困難ですが、Service Worker がブラウザによるナビゲーション リクエストの実行を妨げないように、その努力は価値があります。Workbox のおかげで、ナビゲーションのプリロードをはるかに少ない作業で行えます。workbox-navigation-preload モジュールについて詳しくは、リファレンス ドキュメントをご覧ください