Service Worker を使用して、ネットワークで待機することなくナビゲーション リクエストに応答する。
ナビゲーション リクエストとは、ナビゲーション バーに新しい URL を入力したときや、ページ上のリンクをクリックして新しい URL に移動したときに、ブラウザが作成する HTML ドキュメントに対するリクエストです。これは、Service Worker がパフォーマンスに最も大きく影響する部分です。Service Worker を使用して、ネットワークを待つことなくナビゲーション リクエストに応答することで、ネットワークが利用できない場合でも復元性に加えて、ナビゲーションが確実に高速になります。これは、HTTP キャッシュで可能なことに対して、Service Worker による単一の最大のパフォーマンス向上です。
ネットワークから読み込まれるリソースを特定するガイドで説明されているように、ナビゲーション リクエストは、ネットワーク トラフィックの「ウォーターフォール」で行われる可能性のある多くのリクエストのうち、最初のリクエストになります。ナビゲーション リクエストを介して読み込む HTML は、画像、スクリプト、スタイルなどのサブリソースに対する他のすべてのリクエストのフローを開始します。
Service Worker の fetch
イベント ハンドラ内で FetchEvent
の request.mode
プロパティを確認することで、リクエストがナビゲーションかどうかを判断できます。'navigate'
に設定されている場合は、ナビゲーション リクエストです。
原則として、ナビゲーション リクエストの HTML レスポンスをキャッシュに保存するために、有効期間の長い Cache-Control headers
を使用しないでください。通常、HTML と後続のネットワーク リクエストのチェーンが(妥当な)新しいものになるように、ネットワーク経由で Cache-Control: no-cache
を使って処理します。残念ながら、ユーザーが新しいページに移動するたびにネットワークへの侵入が発生すると、各移動が遅くなる可能性があります。少なくとも、高速にはなります。
アーキテクチャに対するさまざまなアプローチ
ネットワークを回避しつつ、ナビゲーション リクエストにどのように応答するかを考えるのは、簡単ではないかもしれません。適切な方法は、ウェブサイトのアーキテクチャと、ユーザーがアクセスする可能性のある一意の URL の数に大きく依存します。
すべてのケースに当てはまる万能なソリューションはありませんが、以下の一般的なガイドラインを参考にして、どのアプローチが最も適しているかを判断してください。
小規模で静的サイト
ウェブアプリが比較的少ない数(数十など)の一意の URL で構成され、それぞれの URL が異なる静的 HTML ファイルに対応している場合、有効な方法の一つは、それらの HTML ファイルをすべてキャッシュに保存し、適切なキャッシュされた HTML を使用してナビゲーション リクエストに応答することです。
プレキャッシュを使用すると、Service Worker がインストールされたらすぐに HTML を事前にキャッシュに保存し、サイトを再構築して Service Worker を再デプロイするたびにキャッシュされた HTML を更新できます。
または、ユーザーがサイト上の一部の URL にのみアクセスする傾向があるなど、すべての HTML を事前キャッシュすることを避けたい場合は、再検証中に古い再検証を行うランタイム キャッシュ戦略を使用できます。ただし、個々の HTML ドキュメントは個別にキャッシュに保存され、更新されるため、この方法には注意が必要です。HTML にランタイム キャッシュを使用する方法が最も適しているのは、同じユーザーが頻繁に再アクセスする URL が少なく、それらの URL が互いに独立して再検証されても問題ないと判断できる場合です。
シングルページ アプリ
シングルページ アーキテクチャは、最新のウェブ アプリケーションでよく使用されます。この要素では、ユーザーの操作に応じてクライアント側の JavaScript が HTML を変更します。このモデルは、ユーザーがウェブアプリを操作すると History API を使用して現在の URL を変更します。これにより、実質的に「シミュレーション」のナビゲーションになります。その後のナビゲーションは「偽装」かもしれませんが、最初のナビゲーションは実際のものです。ネットワーク上でブロックされないようにすることが重要です。
幸いなことに、シングルページ アーキテクチャを使用している場合は、キャッシュから最初のナビゲーションを提供する簡単なパターンにアプリケーション シェルがあります。このモデルでは、リクエストされた URL に関係なく、Service Worker はナビゲーション リクエストに対して、すでにキャッシュに保存されている単一の HTML ファイルを返します。この HTML は必要最小限のもので、汎用的な読み込みインジケーターやスケルトン コンテンツなどで構成されている必要があります。ブラウザがこの HTML をキャッシュから読み込むと、既存のクライアントサイド JavaScript が引き継いで、元のナビゲーション リクエストから取得した URL に対して正しい HTML コンテンツをレンダリングします。
Workbox には、このアプローチを実装するために必要なツールが用意されています。navigateFallback
option
を使用すると、App Shell として使用する HTML ドキュメントを指定できます。また、この動作を URL のサブセットに制限する許可リストと拒否リストも指定できます。
マルチページ アプリ
ウェブサーバーがサイトの HTML を動的に生成している場合や、一意のページの数が数十を超える場合は、ナビゲーション リクエストを処理する際にネットワークを回避することがはるかに困難になります。「その他」のアドバイスが当てはまるはずです。
ただし、複数ページにわたるアプリのサブセットでは、ウェブサーバーで使用されるロジックを完全に複製して HTML を生成する Service Worker を実装できる場合があります。これは、サーバー環境と Service Worker 環境の間でルーティングとテンプレートの情報を共有できる場合、特にウェブサーバーが JavaScript を使用する場合(ファイル システムへのアクセスなど、Node.js 固有の機能に依存せずに)する場合に最適です。
使用するウェブサーバーがそのカテゴリに該当し、HTML 生成をネットワークから Service Worker に移行するアプローチを検討したい場合は、SPA の向こう側: PWA の代替アーキテクチャのガイダンスをご覧ください。
その他
キャッシュされた HTML でナビゲーション リクエストに応答できない場合は、(HTML 以外の他のリクエストを処理するために)サイトに Service Worker を追加しても、ナビゲーションが遅くならないように対策を講じる必要があります。ナビゲーション リクエストに応答せずに Service Worker を起動すると、若干のレイテンシが発生します(Service Worker を使用して高速で復元性の高いアプリを構築するを参照)。このオーバーヘッドは、ナビゲーション プリロードという機能を有効にしてから、fetch
イベント ハンドラ内にプリロードされているネットワーク レスポンスを使用することで軽減できます。
Workbox は、ナビゲーションのプリロードがサポートされているかどうかを機能によって検出するヘルパー ライブラリを提供しています。サポートされている場合は、ネットワーク レスポンスを使用するように Service Worker に通知するプロセスが簡素化されます。
写真撮影: Aaron Burden、Unsplash より