1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【ServiceWorker】installイベントとactivateイベントの発火タイミングのまとめ

1
Posted at

はじめに

  • オフラインアプリを作成するにあたりService Workerを初めて使ってみた
  • installイベントやactivateイベントの発火タイミングが少し直観的ではなく、理解を定着させるためにアウトプット

installイベントとは

ブラウザに最新のService workerがインストールされたタイミングで発火するイベントです。

Service workerをブラウザにインストールする処理は、navigator.serviceWorker.register()メソッドで行います。

main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";

if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/sw.js");
}

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

こうすることでmain.tsxがマウントされる時にnavigator.serviceWorker.register()メソッドが実行されますが、Service Workerファイルが同じであればインストールはされません。

現在インストール済みのものと1バイトでも違いがあれば新しいService Workerと判断されます。

activateイベントとは

新しいService Workerがインストールされた後、インストール済みのService Workerが制御しているブラウザページがすべて閉じられたときに発火するイベントです。

activate状態とは、Service Workerがブラウザページを制御する準備ができた状態、または制御している状態です。

古いバージョン(インストール済みのService Worker)と新バージョンが同時にブラウザ制御をすることができません。

古いバージョンが制御しているブラウザページをすべて閉じたことが確認できてから、新しい Service Workerの仕事ができる状態になります。

ブラウザページの制御とは

「ブラウザページを制御する」とはそのページ(クライアント)から発生するイベントをService Workerがインターセプト・ハンドリングすることです。

具体的には以下のようなことが可能になります。

  • fetchイベント — ページが行うネットワークリクエストを横取りして、キャッシュを返したり書き換えたりできる
  • pushイベント — サーバーからのプッシュ通知を受け取れる
  • syncイベント — バックグラウンド同期ができる

ページの通信や動作に介入できるイメージです。
制御下にないページのfetchリクエストはService Workerを素通りして普通にネットワークへ行きます。

ブラウザページを制御する準備ができた状態とは

上記でactivate状態の説明を次のように説明しました

activate状態とは、Service Workerがブラウザページを制御する準備ができた状態、または制御している状態です。
「ブラウザページを制御する準備ができた状態」について補足します

新しいService Workerが初めてactivate状態になった段階では、まだブラウザページを制御していません。ブラウザページを制御できるようになるのは、activate状態になった後ブラウザページをロードした後です。

流れを書くと次のような感じです。

Service Workerを更新する
  ↓
ブラウザページを閉じる(古いバージョンの制御が外れる)
  ↓
新しいブラウザページを開く(新バージョンがactivate状態になる)
  ↓
ブラウザページをリロードする(新バージョンがブラウザページを制御する)

activate状態には、activate(待機)状態activate(制御)状態の2種類がある、というイメージです。

新しいService Workerをすぐ反映させたい場合

Service Workerを更新する度にブラウザページを閉じたりするのが面倒な場合、すぐに反映させることができます。

sw.ts
import { precacheAndRoute } from "workbox-precaching";

declare let self: ServiceWorkerGlobalScope;

// Workboxのinjection用
precacheAndRoute(self.__WB_MANIFEST);

self.addEventListener("install", () => {
  // 新しいsw.jsをすぐにアクティブ化する
  self.skipWaiting();
});

self.addEventListener("activate", (event) => {
  event.waitUntil(
    // アクティブ化後すぐに新バージョンのService Workerでページ制御できるようにする
    self.clients.claim(),
  );
});

インストールしたら即座にactivate状態にする

installイベントにself.skipWaiting()メソッドを使うことで、インストールしたらすぐにactivate状態になります。
これのおかげで古いバージョンが制御しているブラウザページを閉じる必要はなくなります。

sw.ts
self.addEventListener("install", () => {
  // 新しいsw.jsをすぐにアクティブ化する
  self.skipWaiting();
});

即座にactivate(制御)状態にする

self.clients.claim()メソッドは、古いバージョンのページ制御を即座に新バージョンへ引き継いでくれるようになります。
event.waitUntil()メソッドはPromiseを引数に受け取り、そのPromiseが解決されるまでService Workerのイベント(installやactivateなど)が終了しないように延命してくれるメソッドです。

sw.ts
self.addEventListener("activate", (event) => {
  event.waitUntil(
    // アクティブ化後すぐに新バージョンのService Workerでページ制御できるようにする
    self.clients.claim(),
  );
});

おわりに

開発中にService workerが反映されずに、問題の切り分けに時間がかかった場面がありました。
整理すると各イベントとブラウザページの制御の関係性がはっきり見えたので、fetchイベントやpushイベントなどインターセプトする処理の実装に注力できそうです。

参考

https://developer.mozilla.org/ja/docs/Web/API/Service_Worker_API/Using_Service_Workers
https://developer.mozilla.org/ja/docs/Web/API/ServiceWorkerContainer/register

JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてください!
▼▼▼

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?