Service Workerを書き始める
概要はなんとなくわかっているつもりだけど、ちゃんと自身で書いたことなかったので書き始めてみる。
service workerとはなんぞやと改めて理解するのに、Googleのドキュメントを読んだ。
概要から始まり、ライフサイクルや、かんたんなチュートリアルが書いてあって、分かりやすく良い感じにまとめられている。
検証環境
ブラウザはGoogle Chromeを用いる
また、基本的にシークレットウィンドウ上で試している。
Service Workerのシンプルなサンプル
Service Workerの物凄くシンプルなサンプルを書いていく。Service Workerのhello world的な。
下記それぞれのファイルをルートに配置する
index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Service Worker Sample</title> </head> <body> <div><h2>Service Worker Sample</h2></div> <script> if ("serviceWorker" in navigator) { window.addEventListener("load", function() { navigator.serviceWorker.register("/sw.js").then( function(registration) { // Registration was successful console.log( "ServiceWorker registration successful with scope: ", registration.scope ); }, function(err) { // registration failed :( console.log("ServiceWorker registration failed: ", err); } ); }); } </script> </body> </html>
sw.js
console.log(hello world)
ローカルでwebサーバを起動させてアクセスする必要があるので、なんとなくbrowser-sync
を入れる
yarn add -D browser-sync
下記コマンドでローカルサーバ立ち上げ (オプション周りは個人の好みが入っている)
yarn browser-sync start --server --files *.html --no-open
これで localhost:3000
にアクセスすると、下記のようなログが表示されているはず
hello world ServiceWorker registration successful with scope: http://localhost:3000/
この状態で下記にアクセスすると、localhost:3000のservice workerが登録されていることが確認できる。
chrome://inspect/#service-workers
また、ブラウザの画面を開いた状態でリロードすると、hello worldは表示されない。
上に貼ったGoogleドキュメントに記述がある
ページが読み込まれるたびに register() メソッドが呼ばれますが、心配はいりません。ブラウザは Service Worker が既に登録されているかどうかを調べ、結果に応じて登録処理をするかしないか判断してくれます。
sw.js
を下記のように書き換えてみる
self.addEventListener('install', function(event) { console.log('install') console.log('hello world') });
一度install
されていれば、下記のログが表示されないことがわかる。
install hello world
次に fetch
を使ってみる
self.addEventListener('install', function(event) { console.log('install') console.log('hello world') }); self.addEventListener('fetch', function(event) { console.log(event); })
画面を開いてからまずは install
のみが呼ばれる。
画面をリロードすると、今度は fetch
が呼ばれるのがわかる。
Service Worker側でHTMLと画像をcacheする
ドキュメントを参考にして下記のようなソースコードを書く
index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Service Worker Sample</title> </head> <body> <div><h2>Service Worker Sample</h2></div> <div><img src="/sample.png" /></div> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js').then( function(registration) { // Registration was successful console.log( 'ServiceWorker registration successful with scope: ', registration.scope ); }, function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); } ); }); } </script> </body> </html>
sw.js
const CACHE_NAME = 'my-site-cache-v1'; const urlsToCache = ['/', '/sample.png']; self.addEventListener('install', function(event) { console.log('===install==='); // Perform install steps event.waitUntil( caches.open(CACHE_NAME).then(function(cache) { console.log({ cache }); console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); }); self.addEventListener('fetch', function(event) { console.log('===fetch==='); console.log(event); event.respondWith( caches.match(event.request).then(function(response) { // Cache hit - return response if (response) { console.log({ response }); return response; } return fetch(event.request); }) ); });
また、ルートにサンプル用の画像ファイル ( sample.png
)を設置している。
ローカルサーバを起動させ、アクセスする。 この時点でservice workerにHTMLと画像がキャッシュされる。
その後、ローカルサーバを停止させて、ブラウザをリロードさせてもservice workerからHTMLと画像は取得できるので、ページ自体は問題なく表示されている。
実際にブラウザ側でキャッシュされているのだということを実感できて面白い。