at backyard

Color my life with the chaos of trouble.

Service Workerを書き始める

概要はなんとなくわかっているつもりだけど、ちゃんと自身で書いたことなかったので書き始めてみる。

service workerとはなんぞやと改めて理解するのに、Googleのドキュメントを読んだ。
概要から始まり、ライフサイクルや、かんたんなチュートリアルが書いてあって、分かりやすく良い感じにまとめられている。

developers.google.com

検証環境

ブラウザは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と画像は取得できるので、ページ自体は問題なく表示されている。

実際にブラウザ側でキャッシュされているのだということを実感できて面白い。