従来のプリフェッチ手法とサービス ワーカーを補完する。
サイト上でタスクを実行するには、通常、複数の手順が必要です。たとえば、e コマース サイトで商品を購入する場合、商品の検索、検索結果のリストから商品の選択、カートへの商品の追加、購入手続きによるオペレーションの完了などがあります。
技術的な用語で言えば、ページ間を移動することは、ナビゲーション リクエストを行うことを意味します。一般に、長時間存続する Cache-Control
ヘッダーを使用して、ナビゲーション リクエストの HTML レスポンスをキャッシュすることはおすすめしません。通常は、HTML と後続のネットワーク リクエストのチェーンが(合理的に)最新であることを確認するために、Cache-Control: no-cache
を使用してネットワーク経由で処理する必要があります。ユーザーが新しいページに移動するたびにネットワークにアクセスする必要があるため、各ページへの移動が遅くなる可能性があります。少なくとも、信頼性の高い高速なページ遷移は実現できません。
これらのリクエストを高速化するには、ユーザーの操作を予測できる場合は、これらのページとアセットを事前にリクエストし、ユーザーがリンクをクリックするまで短時間キャッシュに保持します。この手法はprefetchingと呼ばれ、通常はページに <link rel="prefetch">
タグを追加して、プリフェッチするリソースを指定することで実装されます。
このガイドでは、従来のプリフェッチ手法の補完として サービス ワーカーを使用するさまざまな方法について説明します。
本番環境のケース
MercadoLibre は、ラテンアメリカ最大の e コマース サイトです。ナビゲーションを高速化するために、フロー内の一部に <link rel="prefetch">
タグを動的に挿入します。たとえば、リスティング ページでは、ユーザーがリスティングの一番下までスクロールするとすぐに、次の検索結果ページが取得されます。
プリフェッチされたファイルは「低」の優先度でリクエストされ、(リソースがキャッシュに保存可能かどうかに応じて)HTTP キャッシュまたはメモリキャッシュにブラウザによって異なる時間だけ保存されます。たとえば、Chrome 85 ではこの値は 5 分です。リソースは 5 分間保持され、その後はリソースの通常の Cache-Control
ルールが適用されます。
Service Worker のキャッシュを使用すると、プリフェッチ リソースの存続期間を 5 分間を超えて延長できます。
たとえば、イタリアのスポーツ ポータル Virgilio Sport は、サービス ワーカーを使用して、ホームページで最も人気のある投稿をプリフェッチしています。また、Network Information API を使用して、2G 接続を使用しているユーザーに対してプリフェッチが行われないようにしています。
その結果、Virgilio Sport では 3 週間にわたる観察で、記事へのナビゲーションの読み込み時間が78% 改善され、記事のインプレッション数が45% 増加しました。
Workbox でプリキャッシュを実装する
次のセクションでは、Workbox を使用して、<link rel="prefetch">
の補完として使用できる、またはこのタスクをサービス ワーカーに完全に委任することで、<link rel="prefetch">
の代わりに使用できる、サービス ワーカーにさまざまなキャッシュ保存手法を実装する方法について説明します。
1. 静的ページとページのサブリソースをプリキャッシュする
事前キャッシュは、インストール中にファイルをキャッシュに保存する Service Worker の機能です。
次のケースでは、プリキャッシュを使用して、プリフェッチと同様の目標(ナビゲーションを高速化)を達成します。
静的ページのプリキャッシュ
ビルド時に生成されるページ(about.html
、contact.html
など)や完全に静的なサイトの場合は、サイトのドキュメントをプリキャッシュ リストに追加するだけで、ユーザーがアクセスするたびにキャッシュに保存されます。
workbox.precaching.precacheAndRoute([
{url: '/about.html', revision: 'abcd1234'},
// ... other entries ...
]);
ページのサブリソースをプリキャッシュに保存する
サイトのさまざまなセクションで使用される可能性のある静的アセット(JavaScript、CSS など)をプリキャッシュに保存することは、一般的なベスト プラクティスであり、プリフェッチ シナリオでパフォーマンスをさらに向上させることができます。
e コマース サイト内のナビゲーションを高速化するには、リスティング ページで <link rel="prefetch">
タグを使用して、リスティング ページの最初の数件の商品の詳細ページをプリフェッチします。商品ページのサブリソースをすでにプリキャッシュしている場合は、ナビゲーションをさらに高速化できます。
これを実装する手順は次のとおりです。
- ページに
<link rel="prefetch">
タグを追加します。
<link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
- ページのサブリソースをサービス ワーカーのプリキャッシュ リストに追加します。
workbox.precaching.precacheAndRoute([
'/styles/product-page.ac29.css',
// ... other entries ...
]);
2. プリフェッチ リソースの存続時間を延長する
前述のように、<link rel="prefetch">
はリソースを取得して HTTP キャッシュに一定時間保持します。その後、リソースの Cache-Control
ルールが適用されます。Chrome 85 では、この値は 5 分です。
Service Worker を使用すると、プリフェッチ ページの存続期間を延長できるだけでなく、それらのリソースをオフラインで使用できるという利点もあります。
上の例では、商品ページのプリフェッチに使用される <link rel="prefetch">
を、Workbox ランタイム キャッシュ戦略で補完できます。
実装方法は次のとおりです。
- ページに
<link rel="prefetch">
タグを追加します。
<link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
- 次のタイプのリクエストに対して、Service Worker に実行時のキャッシング戦略を実装します。
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'document-cache',
plugins: [
new workbox.expiration.Plugin({
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
],
});
この場合、再検証中の古いデータを使用する戦略を選択しました。この戦略では、キャッシュとネットワークの両方からページを同時にリクエストできます。レスポンスは、キャッシュから取得されます(キャッシュが利用可能な場合)。キャッシュが利用できない場合は、ネットワークから取得されます。キャッシュは、リクエストが成功するたびにネットワーク レスポンスに合わせて常に最新の状態に保たれます。
3. プリフェッチを Service Worker に委任する
ほとんどの場合、<link rel="prefetch">
を使用することをおすすめします。このタグは、プリフェッチを可能な限り効率的に行うように設計されたリソースヒントです。
ただし、このタスクをサービス ワーカーに完全に委任したほうがよい場合もあります。たとえば、クライアントサイドでレンダリングされた商品リスティング ページで最初の数件の商品をプリフェッチするには、API レスポンスに基づいて、ページに複数の <link rel="prefetch">
タグを動的に挿入する必要があります。これにより、ページのメインスレッドで時間が一時的に消費され、実装が難しくなる可能性があります。
このような場合は、「ページから Service Worker への通信戦略」を使用して、プリフェッチのタスクを Service Worker に完全に委任します。このタイプの通信は、worker.postMessage() を使用して実現できます。
Workbox Window パッケージは、このタイプの通信を簡素化し、実行される基盤となる呼び出しの多くの詳細を抽象化します。
Workbox Window によるプリフェッチは、次の方法で実装できます。
- ページで: メッセージのタイプとプリフェッチする URL のリストを渡して Service Worker を呼び出します。
const wb = new Workbox('/sw.js');
wb.register();
const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: […]});
- サービス ワーカーで、プリフェッチする URL ごとに
fetch()
リクエストを発行するメッセージ ハンドラを実装します。
addEventListener('message', (event) => {
if (event.data.type === 'PREFETCH_URLS') {
// Fetch URLs and store them in the cache
}
});