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

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

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

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

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

連続したアクションを示す 2 つのセグメントがある黄色と青色のバー。1 つ目のセグメントは黄色で「SW boot」と書かれ、青いセグメントには「Navigation request」と書かれている。

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

2 つの同時実行アクションを表す 2 つの棒が左揃えで積み重ねられて配置されている。黄色のバーは「SW boot」、青色のバーには「Navigation request」というラベルが付いています。

ナビゲーションのプリロードは、Service Worker を使用するサイトのパフォーマンス最適化に効果的ですが、あらゆる状況で有効にする必要があるわけではありません。特に、事前キャッシュされた App Shell を使用しているサイトでは、ナビゲーションのプリロードは必要ありません。キャッシュは、ナビゲーションの遅延なしで App Shell マークアップのナビゲーション リクエストを処理するためです。このような場合、プリロードされたレスポンスは無駄になりますが、これは良いことではありません。

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

ワークボックスでナビゲーション プリロードを使用する

Workbox を利用しない Service Worker で、ナビゲーションのプリロードを直接使用するのは簡単ではありません。まず、一部のブラウザでは対応していません。次に、正しく予測するのは難しいことがあります。使用方法は、Jake Archibald による解説で直接学ぶことができます。

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

以上のように、Workbox を使用してネットワーク ファーストの戦略ハンドラでナビゲーション リクエストを処理することで、ブラウザのサポートでナビゲーション プリロードのメリットが得られます。

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 の処理に関するログが多く記録されます。ワークボックスでナビゲーション プリロードが機能しているかどうかを確認する場合、ナビゲーション リクエスト中にサポート ブラウザでコンソールを開くと、次のようなログメッセージが表示されます。

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

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

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

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

このような場合、プリロード リクエストがデフォルト値の true に設定された Service-Worker-Navigation-Preload ヘッダーとともに送信されると便利です。

Service-Worker-Navigation-Preload: true

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

まとめ

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