Service Worker をデプロイすると、ウェブサイトの動作が予想外の方法で変わることがあります。Workbox を使用すると、Service Worker を簡単に記述してデプロイできるため、デプロイ後に Service Worker がウェブサイトに与える影響の一部を見落としやすくなる場合があります。
これは、Workbox を使用しても悪い結果が生じるということではなく、Workbox が提供する利便性のために、Service Worker のデプロイにどう関係するかを知らなければ、問題にぶつかりやすくなるだけです。
プレキャッシュの注意点
プリキャッシュについては、これらのドキュメントで以前説明しましたが、バックファイアの方法が完全には取り上げられていません。プレキャッシュを適用するアセットが多すぎる場合や、ページで重要なアセットの読み込みが完了する前に Service Worker が登録されている場合は、問題が発生する可能性があります。
workbox-webpack-plugin
のデフォルトの動作は、生成されたアセットを自動的に事前キャッシュするように Service Worker に指示する動作ですが、導入へのハードルが低いため、これは見落としやすいという問題があります。
インストール中に Service Worker がアセットを事前キャッシュに保存すると、1 つ以上のネットワーク リクエストが同時に開始されます。そのため、タイミングが正確でないと、ユーザー エクスペリエンスに支障をきたすおそれがあります。タイミングが正確であったとしても、事前キャッシュされたアセットの量がなんらかの形で制限されなければ、データが無駄になる可能性があります。
すべてはタイミング
Service Worker がなんらかの事前キャッシュを保存する場合は、それが登録された時刻が重要になります。Service Worker は多くの場合、インライン <script>
要素を使用して登録されます。つまり、ページの重要なアセットが読み込まれる前に、HTML パーサーで Service Worker 登録コードが検出されることがあります。
これが問題です。最悪のケースでは、Service Worker はパフォーマンスに依存せず、パフォーマンスを悪化させないことが理想的です。ユーザーの選択を優先して、ページの load
イベントが発生したときに Service Worker を登録します。これにより、プレキャッシュによってページの重要なアセットの読み込みが妨げられる可能性が低減します。これにより、後で必要のないアセットのネットワーク リクエストに対処する必要がなくなり、ページをインタラクティブに高速化できます。
データ使用量に配慮する
タイミングにかかわらず、プレキャッシュにはネットワーク リクエストの送信が含まれます。プリキャッシュするアセットのマニフェストを慎重にキュレートしないと、ある程度の無駄になる可能性があります。
データの無駄はプレキャッシュのトレードオフになる可能性がありますが、すべてのユーザーが高速なインターネットや無制限のデータプランを利用できるわけではありません。プレキャッシュを行う際は、コストのかかる想定をするよりも、特に大きなアセットを切り取ってランタイム キャッシュに任せて取得することをおすすめします。
Service Worker の起動によってネットワーク リクエストが遅延することがある
Service Worker は、ウェブサイトの他のコードとは別のプロセスで実行されます。このプロセスは頻繁に開始および停止します。Service Worker がアクティブでない後にフェッチ イベントを処理する必要がある場合、ブラウザはまず Service Worker の起動に時間を費やす必要があります。ネットワークではなくキャッシュからレスポンスを提供するメリットに比べると、リクエストが処理できるようになる前の余分なオーバーヘッドは小さなものです。
キャッシュからは提供できず、ネットワークに移動する必要がある場合(特にナビゲーション リクエストを処理する場合)、起動時間によって常に遅延が発生します。デバイスの機能や CPU の負荷によっては、Service Worker の起動が遅いため、ナビゲーション リクエストで顕著な遅延が発生することがあります。この遅延を認識せずに Service Worker をデプロイすると、ユーザーが予期せぬパフォーマンスの影響を受ける可能性があります。
この問題はナビゲーション プリロードで解決されましたが、一部のブラウザではまだサポートされていません。ただし、この点については検討する価値があります。これについては、このドキュメントの後半で説明します。
キャッシュ ファースト戦略ではバックファイアが
最初にキャッシュを参照する(またはキャッシュのみを参照する)キャッシュ戦略は、オフライン アクセスとパフォーマンスの両方に役立ちます。ただし、一部のケースでは問題を引き起こす傾向があります。
バージョニングされていない静的アセットの実行時キャッシュ
Bundler は通常、ファイル名にコンテンツ ベースのハッシュを含めて静的アセットをバージョニングします(例: styles.a4edf38c.css
)。静的アセットについては最初にキャッシュを参照し、ページ マークアップにネットワーク ファースト戦略を使用するキャッシュ戦略を使用する Service Worker では、更新されたアセットが、常にネットワークから取得されるマークアップで参照されるため、キャッシュ保存の問題は発生しません。
このような戦略を使用している実行時に、バージョニングされていない静的アセットがキャッシュに保存されると、問題が発生します。ウェブサイトの機能が app.js
によって提供され、キャッシュ ファーストのランタイム戦略が採用されている場合、ファイル名を変更することなく app.js
が後で更新されると、最初にキャッシュに保存されたバージョンは更新ではなくキャッシュから引き続き提供されます。
この問題を解決するには、ネットワーク ファースト、ステイル更新中など、ネットワークを参照して更新を行う戦略を使用します。または、Workbox のプレキャッシュ ロジックによって最新の状態が維持されるため、ビルドツールでこれらのアセットのプリキャッシュ マニフェストを生成することもできます。
いずれにしても、静的アセットのバージョニングはアセット名やクエリ文字列のハッシュによって行うことを強くおすすめします。これにより、静的アセットにキャッシュ ファーストのランタイム戦略を使用する Service Worker で、古いアセットの問題を回避できます。
保存容量に注意する
Service Worker の更新は随時ロールアウトされ、更新がロールアウトされると、通常、新しい Service Worker の有効化中に、期限切れになった名前を持つ古いキャッシュがプルーニングされます。
ただし、一部の Service Worker のイテレーションは長期間に及ぶことや、新しい更新でキャッシュ名が更新されないことがあります。この場合、更新がロールアウトされると、古い静的アセットがキャッシュに蓄積される可能性があります。保存容量はブラウザによって設定されるため、上限はブラウザによって異なる場合があります。これが、そうしたユーザーの注意を払うべき理由です。
Workbox はこれらの問題を緩和しますが、保存容量の割り当てを超過する可能性があります。workbox-expiration モジュールを使用すると、キャッシュをより細かく制御できます。
心配は無用
Service Worker のデプロイは簡単なことではありません。しかし、Workbox を使用して Service Worker をデプロイすることの意味について、ちょっとした計画や注意深さがあれば、怖くはありません。このドキュメントを読めば、これらの懸念事項を慎重に乗り越えるうえで役立ちます。