webページを更新しても Status Code:OK (from ServiceWorker) で頑固に古いバージョンが表示されるときの対処法


発生した現象

WordPressが使われていたサイトでNext.js によりサイトのリニューアルをした
そのときトップページだけ通常アクセスや通常リロードで古いサイトが表示された
スーパーリロードすると新しいサイトが表示された
スーパーリロード後でも通常アクセスや通常リロードで古いサイトが表示された
ブラウザのdevtoolsにはページへのアクセスに対し Status Code:OK (from ServiceWorker) が表示されていた

原因

旧サイトにServiceWorker(今回は /serviceWorker.js というリソース)があり、トップページやそのリソースをキャッシュし self.addEventListener('fetch'... でレスポンスをキャッシュに差し替える処理が書かれていた
それがブラウザに登録された状態で新サイトに置き換わり、 /serviceWorker.js がなくなって 404 (from ServiceWorker) になった

そしてServiceWorkerの仕様によると

新しい Worker は、ステータス コードが正常でないか(たとえば 404)、解析に失敗するか、実行中にエラーをスローするか、インストール時に棄却される場合は破棄されますが、現行の Worker はアクティブなままです。

ということなので、24時間更新チェックが走ろうともキャッシュを保持して返すWorkerはアクティブなまま残ったと思われる

原因の原因

WordPressのThe ThorというテーマにPWA設定があり、オンになっていた
これが /serviceWorker.js を設置していた

ダメな解決策

  • Chromeの問題ドメインのサイトのデータを全削除
  • Chrome devtoolsの Application > Service Workers からUnregisterする

これらのどちらかで直るが、自分しか直らないので意味がない

解決策

以前あったのと同じServiceWorkerのファイルを作り、以下のように、全てのキャッシュを消してunregisterするような内容に置き換える
これにより、旧サイトにアクセスしたブラウザに登録されたServiceWorkerが新サイトにアクセスした時点で消える

if (navigator.serviceWorker) {
  navigator.serviceWorker.getRegistrations().then(function (registrations) {
    for (let registration of registrations) {
      registration.unregister();
    }
  });
}

self.addEventListener('install', function (event) {
  event.waitUntil(skipWaiting());
});

self.addEventListener('activate', function (event) {
  event.waitUntil(self.clients.claim());
  event.waitUntil(
    caches.keys().then(function (cacheNames) {
      return Promise.all(
        cacheNames.map(function (cacheName) {
          return caches.delete(cacheName);
        }),
      );
    }),
  );
});

感想

  • ServiceWorkerのキャッシュ強すぎだろ…。24時間チェックで404になってたらunregisterしといてくれ
  • WordPressの テーマに PWAの設定があり、設定されていたなんて予想外だった(自分がアタリをつけれたのはwordpressプラグインまでで、同僚が見つけてくれないと分からないままだった)。WordPressってそういうこともあるんですね
  • 自分自身を 404 (from ServiceWorker) と言ってるのを見たときはちょっと面白かった

参考