要約
Chrome 68 以降、サービス ワーカー スクリプトの更新を確認する HTTP リクエストは、デフォルトで HTTP キャッシュによって処理されなくなります。これは、サービス ワーカー スクリプトに誤って Cache-Control
ヘッダーを設定すると更新が遅れるというデベロッパーの一般的な問題を回避します。
Cache-Control: max-age=0
で /service-worker.js
スクリプトを配信して、すでに HTTP キャッシュをオプトアウトしている場合は、新しいデフォルト動作による変更は発生しません。
また、Chrome 78 以降では、バイト単位の比較が importScripts()
を介して Service Worker に読み込まれるスクリプトに適用されます。インポートされたスクリプトに変更を加えると、トップレベルの Service Worker の変更と同様に、Service Worker の更新フローがトリガーされます。
背景
サービス ワーカーのスコープ内の新しいページに移動するたびに、JavaScript から registration.update()
を明示的に呼び出すか、push
イベントまたは sync
イベントによってサービス ワーカーが「起動」されたときに、ブラウザは navigator.serviceWorker.register()
呼び出しに最初に渡された JavaScript リソースを並行してリクエストし、サービス ワーカー スクリプトの更新を探します。
この記事では、URL が /service-worker.js
で、サービス ワーカー内で実行される追加のコードを読み込む importScripts()
への呼び出しが 1 回含まれているとします。
// Inside our /service-worker.js file:
importScripts('path/to/import.js');
// Other top-level code goes here.
変更内容
Chrome 68 より前は、/service-worker.js
の更新リクエストは(ほとんどの取得と同様に)HTTP キャッシュを介して行われていました。つまり、スクリプトが最初に Cache-Control:
max-age=600
で送信された場合、次の 600 秒(10 分)以内の更新はネットワークに送信されず、ユーザーが最新バージョンのサービス ワーカーを受信できない可能性があります。ただし、max-age
が 86400(24 時間)より大きい場合は、ユーザーが特定のバージョンに永続的に固定されないように、86400 として扱われます。
68 以降、サービス ワーカー スクリプトの更新をリクエストする際に HTTP キャッシュは無視されるため、既存のウェブ アプリケーションでは、サービス ワーカー スクリプトのリクエスト頻度が増加する可能性があります。importScripts
のリクエストは引き続き HTTP キャッシュを経由します。ただし、これはデフォルト設定にすぎません。新しい登録オプション updateViaCache
を使用すると、この動作を制御できます。
updateViaCache
デベロッパーは、navigator.serviceWorker.register()
を呼び出すときに新しいオプション(updateViaCache
パラメータ)を渡せるようになりました。'imports'
、'all'
、'none'
のいずれかの値を指定します。
この値によって、更新されたサービス ワーカー リソースを確認する HTTP リクエストを実行する際に、ブラウザの標準の HTTP キャッシュが使用されるかどうか、また使用される場合はどのように使用されるかが決まります。
'imports'
に設定すると、/service-worker.js
スクリプトの更新を確認するときに HTTP キャッシュは参照されませんが、インポートされたスクリプト(この例ではpath/to/import.js
)を取得するときに参照されます。これはデフォルトであり、Chrome 68 以降の動作と同じです。'all'
に設定すると、トップレベルの/service-worker.js
スクリプトと、サービス ワーカー内にインポートされたスクリプト(path/to/import.js
など)の両方に対してリクエストを行うときに、HTTP キャッシュが参照されます。このオプションは、Chrome 68 より前の Chrome の以前の動作に対応しています。'none'
に設定すると、トップレベルの/service-worker.js
またはインポートされたスクリプト(仮想のpath/to/import.js
など)のリクエストを行うときに HTTP キャッシュは参照されません。
たとえば、次のコードはサービス ワーカーを登録し、/service-worker.js
スクリプトまたは /service-worker.js
内の importScripts()
を介して参照されるスクリプトの更新を確認するときに、HTTP キャッシュが参照されないようにします。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {
updateViaCache: 'none',
// Optionally, set 'scope' here, if needed.
});
}
インポートされたスクリプトの更新を確認します
Chrome 78 より前は、importScripts()
経由で読み込まれたサービス ワーカー スクリプトは 1 回だけ取得されていました(updateViaCache
の構成に応じて、まず HTTP キャッシュで確認するか、ネットワーク経由で確認します)。最初の取得後、ブラウザによって内部に保存され、再取得されることはありません。
すでにインストールされているサービス ワーカーにインポートされたスクリプトの変更を強制的に適用する唯一の方法は、スクリプトの URL を変更することでした。通常は、semver 値(例: importScripts('https://example.com/v1.1.0/index.js')
)を追加するか、コンテンツのハッシュを含める(例: importScripts('https://example.com/index.abcd1234.js')
)ことで変更します。インポートされた URL を変更すると、トップレベルのサービス ワーカー スクリプトのコンテンツが変更され、サービス ワーカーの更新フローがトリガーされます。
Chrome 78 以降では、トップレベルのサービス ワーカー ファイルの更新チェックが実行されるたびに、インポートされたスクリプトの内容が変更されていないかどうかを同時に確認します。使用される Cache-Control
ヘッダーに応じて、これらのインポートされたスクリプト チェックは、updateViaCache
が 'all'
または 'imports'
(デフォルト値)に設定されている場合は HTTP キャッシュによって実行される場合があります。また、updateViaCache
が 'none'
に設定されている場合は、ネットワークに対して直接実行される場合があります。
インポートされたスクリプトの更新チェックで、サービス ワーカーによって以前に保存されたものとバイト単位で差異が検出されると、トップレベルのサービス ワーカー ファイルが同じままでも、サービス ワーカーの完全な更新フローがトリガーされます。
Chrome 78 の動作は、Firefox が数年前の Firefox 56 で実装したものと同じです。Safari ではすでにこの動作が実装されています。
デベロッパーが行う必要があることは何ですか?
Cache-Control: max-age=0
(または同様の値)で /service-worker.js
スクリプトを配信することで、/service-worker.js
スクリプトの HTTP キャッシュを事実上無効にしている場合、新しいデフォルト動作による変更は発生しません。
意図的に、またはホスティング環境のデフォルトであるために HTTP キャッシュを有効にして /service-worker.js
スクリプトを配信している場合、サーバーに送信される /service-worker.js
の追加の HTTP リクエストが増加する可能性があります。これは、以前は HTTP キャッシュによって処理されていたリクエストです。Cache-Control
ヘッダー値が /service-worker.js
の更新頻度に影響を与え続けるようにするには、サービス ワーカーの登録時に updateViaCache: 'all'
を明示的に設定する必要があります。
古いバージョンのブラウザを使用しているユーザーが長く残る可能性があることを考えると、新しいブラウザでは無視される可能性がありますが、サービス ワーカー スクリプトに Cache-Control: max-age=0
HTTP ヘッダーを設定し続けることをおすすめします。
デベロッパーは、この機会に、インポートされたスクリプトを HTTP キャッシュから明示的に除外するかどうかを決定し、必要に応じてサービス ワーカーの登録に updateViaCache: 'none'
を追加できます。
インポートされたスクリプトの提供
Chrome 78 以降、importScripts()
経由で読み込まれるリソースの更新がチェックされるため、リソースの HTTP リクエストの受信が増える可能性があります。
この追加の HTTP トラフィックを回避するには、URL に semver またはハッシュを含むスクリプトを配信するときに、長時間の Cache-Control
ヘッダーを設定し、'imports'
のデフォルトの updateViaCache
動作に依存します。
インポートされたスクリプトの頻繁な更新を確認したい場合は、Cache-Control: max-age=0
でスクリプトを提供するか、updateViaCache: 'none'
を使用するようにしてください。
関連情報
Jake Archibald による「The Service Worker Lifecycle」と「Caching best practices & max-age gotchas」は、ウェブに何かをデプロイするすべてのデベロッパーにおすすめの読み物です。