Service Workerのライフサイクルをちゃんと理解する
PWA(Progressive Web App)で使われている「Service Worker」について
動きを正しく理解するために処理の流れを追っていきます。
主に以下の内容を見ながら学んでいきます。
https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle?hl=ja
↑を検証用に少し手を加えてます。
https://github.com/morix1500/service_worker_test
最初のService Worker
まだService Workerが登録されていないときの動きを追っていきます。
https://github.com/morix1500/service_worker_test/tree/master/v1
ブラウザで http://localhost/v1/in-scope/ を閲覧します。
# consoleログ SW registered! ServiceWorkerRegistration {installing: ServiceWorker, waiting: null, active: null, navigationPreload: NavigationPreloadManager, scope: "http://localhost/v1/in-scope/", …} V1 installing… V1 now ready to handle fetches! # この時、ブラウザでは「man.png」が表示された。
つまり最初にService Workerが登録されるときは
- まずregisterイベントが走り、Service Workerが登録される
- 次にService Workerのinstallイベントが走る
- 最後にService Workerのactivateイベントが走る
- Service Workerのfetchイベントは走らない
というのがわかりました。
次にページを更新してみたときのconsoleログを見てみます
# consoleログ SW registered! ServiceWorkerRegistration {installing: null, waiting: null, active: ServiceWorker, navigationPreload: NavigationPreloadManager, scope: "http://localhost/v1/in-scope/", …} URL {href: "http://localhost/v1/in-scope/man.png", origin: "http://localhost", protocol: "http:", username: "", password: "", …} # この時、ブラウザでは「woman.png」が表示された。
Service Worker登録後にページを更新してみると
- registerイベントが走る
- Service Workerのfetchイベントが走る
- fetch内の
event.respondWith
が実行される - Service Workerのinstallとactivateイベントは走らない
さて、Service WorkerのScopeは以下のようになってます。
// /v1/in-scope/index.html navigator.serviceWorker.register('/v1/sw.js', {scope: '/v1/in-scope/'})
スコープを /v1/in-scope/
にしてます。
ここで http://localhost/v1/out-scope を見てみます。
# consoleログ # Service Worker登録 SW registered! ServiceWorkerRegistration {installing: ServiceWorker, waiting: null, active: null, navigationPreload: NavigationPreloadManager, scope: "http://localhost/v1/in-scope/", …} V1 installing… V1 now ready to handle fetches! # ページ更新 SW registered! ServiceWorkerRegistration {installing: null, waiting: null, active: ServiceWorker, navigationPreload: NavigationPreloadManager, scope: "http://localhost/v1/in-scope/", …}
このことからわかるのは
- スコープを
/v1/in-scope/
にしてるので、スコープ外のものはfetchイベントが走らない
ということです。
Service Workerのアップデート
続いてService Workerのアップデート時の挙動を見てみます。
確認手順としては
- 上記のv1のソースをv2としてコピー
- v2のソースで「v1」となっているところを「v2」に置換
- http://localhost/v2/in-scope/ を開く
- woman.png が表示されているのを確認する
- sw.jsを https://github.com/morix1500/service_worker_test/blob/master/v2/sw.js にする
v2のソースは以下です。
https://github.com/morix1500/service_worker_test/tree/master/v2
# Consoleログ SW registered! ServiceWorkerRegistration {installing: null, waiting: null, active: ServiceWorker, navigationPreload: NavigationPreloadManager, scope: "http://localhost/v2/in-scope/", …} V2 installing… # この時ブラウザではwoman.pngが表示される
Service WorkerのStatusは以下のようになっていました。
その後、ページを更新してもwoman.png が出続け、旧Service Workerで表示されていたConsoleログが表示されました。
これまででわかること
- Service Workerが更新されるとService Workerのinstallイベントが走る
- ブラウザ画面上の挙動は旧Service Workerの動作になる
- ページ更新だけだと新Service WorkerのActivateイベントが走らない
ではこの状態でブラウザのタブを閉じ、開きなおします。
# Consoleログ V2 installing… delete chache: static-v1 V2 now ready to handle fetches! URL SW registered! ServiceWorkerRegistration {installing: null, waiting: null, active: ServiceWorker, navigationPreload: NavigationPreloadManager, scope: "http://localhost/v2/in-scope/", …} URL {href: "http://localhost/v2/in-scope/man.png", origin: "http://localhost", protocol: "http:", username: "", password: "", …} # この時ブラウザではgohan.pngが表示された
このことからわかるのは
- タブの開きなおしで新しいService Workerが動く
またテクニックとして、キャッシュのバージョニングを行っています。
v1では「static-v1」というキャッシュを作成し、そこにwoman.pngのキャッシュを追加してました。
Service Workerのバージョンアップをする場合、キャッシュを切り替える必要があるので
「static-v2」というキャッシュ名に変更しています。
バージョンアップ時に旧バージョンのキャッシュを削除するようにしています。
最後に
ふわっと理解していたService Workerのライフサイクルをちゃんと動きを追って理解できました!