定義
Service Worker(ページとネットワークの間でリクエストを横取りするバックグラウンドスクリプト)にオフライン対策の「シェルフォールバック」を入れるとき、ネットワークが失敗したらアプリの外殻 HTML(例: /)を代わりに返すように書きがちだ。しかしこのフォールバックを すべてのリクエストに掛けると、画像・API リクエストが失敗したときにも HTML を返して <img> が崩れ、blob がシェルキャッシュに無限に積み上がる。シェルフォールバックは必ず request.mode === 'navigate' の文書遷移リクエストにだけ 掛けなければならない。
シェル(app shell) は画面の骨格を持つ最小 HTML、request.mode はそのリクエストがページ遷移なのか(navigate)、画像・スクリプトのような下位リソースなのかを区別する印だ。
なぜ必要か
症状: 写真が崩れて見え、時間が経つほどブラウザのストレージが得体の知れないデータで膨れ上がる。原因は、SW がすべての同一オリジン GET を横取りし、失敗時にシェル("/")へフォールバックするように書かれていることだ。写真リクエストがネットワーク失敗でシェルフォールバックに乗ると、<img> が画像の代わりに HTML 文書を受け取ってレンダリングに失敗する。さらにその HTML が写真の URL をキーにキャッシュへ積まれ、ストレージが汚染される。
文書遷移(ページロード)だけシェルへフォールバックすれば、画像・API・静的アセットはネットワーク結果(またはそれぞれのキャッシュ戦略)をそのまま受け取り、この汚染が消える。
動作原理
核心は「シェルは文書リクエストのフォールバックにすぎない」ということだ。画像・API にはそれぞれのポリシー(例: 画像には stale-while-revalidate キャッシュ、API はネットワーク直行)を別に与える。
実務適用
- SW のキャッシュ戦略をリクエスト種別ごとに分岐する:
navigate→ シェルフォールバック、画像 GET → SWR キャッシュ、API → ネットワーク(+オフラインキュー)。 - 既に汚染されたキャッシュがあれば、キャッシュのバージョンを上げて(
v1→v2)過去の項目を purge する。 - シェルフォールバックを入れる前に「このフォールバックは文書でないリクエストにも掛かるか?」を必ず確認する。
トレードオフ
- navigation 限定のシェルフォールバック: オフラインでもページの骨格は表示され、画像・API は崩れた HTML の代わりに正常な失敗(空の画像/エラー)として処理される。代わりにリクエスト種別ごとの分岐を自分で書かねばならない。
- 全体シェルフォールバック(アンチパターン): コードは短いが、画像崩れ + キャッシュ汚染を招く。
使ってはいけない場合
- SW をそもそも使わないアプリ — サーバー CDN・HTTP キャッシュで十分かをまず見る。
- オフライン文書の表示が不要な場合 — シェルフォールバックそのものが不要。
よくある間違い
- すべての GET にシェルフォールバックを掛けて、画像・API の失敗に HTML を返す。
- フォールバックで受け取った HTML がリソースの URL をキーにキャッシュへ積まれ、ストレージ汚染。
- キャッシュ汚染を直した後にキャッシュのバージョンを上げず、過去の汚染分が残る。
関連概念
- service-worker-stale-while-revalidate — 画像など下位リソースのキャッシュ戦略
- server-image-proxy-transcoding-cache — プロキシ画像 URL とキャッシュの役割分担