2018年5月22日火曜日

Service Worker 超入門

概要

先日の Google I/O 2018 などで更に勢いがました PWA ですがその基本的な知識として Service Worker があります
全く触ったことがなかったので今回はローカルキャッシュ機能を試してみました

環境

  • macOS 10.13.4
  • Google Chrome 66.0.3359.181

事前準備

今回は localhost を使います
実際に運用するときは Service Worker は https でないと動作しないようです

またページをホストするミドルウェアを用意しておいてください
特に指定はないので Apache Httpd なり nginx なりお好きなものを使ってください
ちなみに自分は Sinatra で動かしています
以下では http://localhost:9292/sw_test で動いているページを Service Worker 化します

HTML ファイルの準備

今回はオフラインキャッシュ機能を使います
簡単に言うと http://localhost:9292/sw_test にオフライン状態でもアクセスできるようにします
「localhost なんだからオフラインでもアクセスできるだろ」と思いますがローカルホストのプロセスを停止していてもアクセスできるようになります

<html>
<head>
<script>
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service_worker.js', { scope: '/sw_test' }).then(function(reg) {                             
    if(reg.installing) {
      console.log('Service worker installing');
    } else if(reg.waiting) {
      console.log('Service worker installed');
    } else if(reg.active) {
      console.log('Service worker active');
    }
  }).catch(function(error) {
    console.log('Registration failed with ' + error);
  });
}
</script>
</head>
<body>
test page
</body>

言わずもがなポイントは <script> タグ内の内容です
やっていることは /service_worker.js の登録になります
この専用の JavaScript を登録することでオフラインでもページが描画できるようにします
navigator.serviceWorker.register することで登録でき、それぞれのイベントに応じてログを出力しています

あと大事な概念としては「スコープ」があります
これも簡単に説明すると

Service Worker 化するページの範囲

を指定します
今回であれば /sw_test のページのみを Service Worker 化するのでそれを指定しています
サイト全体を対象にする場合は / と指定します

service_worker.js の作成

キモの部分となる Service Worker に処理させる内容をこの service_worker.js に記載します
service_worker.js は今回であれば http://localhost:9292/service_worker.js で見えるようにしておいてください

ちなみに JavaScript だから http://localhost:9292/js/service_worker.js という感じで配信したいという人もいると思いますがこれだと動きません (今回の場合は)
なぜかというと service_worker.js/sw_test の親もしくは子の範囲にいないからです
もう少し説明すると /sw_test/service_worker.js で配信するなら動作しますが、/sw_test2/service_worker.js だと動作しません
特にこだわりがないのであればルートに配置しておくのが無難だと思います

今回はオフライン時にキャッシュしたページを表示させるだけの処理を記載します
まず全体は以下のとおりです

let version = '0.1';

self.addEventListener('install', e => {
  let timeStamp = Date.now();
  e.waitUntil(
    caches.open('mismith').then(cache => {
      return cache.addAll([
        `/sw_test`
      ])
      .then(() => self.skipWaiting());
    })
  )
});

self.addEventListener('activate',  event => {
  event.waitUntil(self.clients.claim());
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request, {ignoreSearch:true}).then(response => {                                                          
      console.log('fetching');
      return response || fetch(event.request);
    })
  );
});

やっている処理を大きく 3 つです

  • インストール時に Service Worker がキャッシュするページを指定
  • Service Worker が activate したら直ちに起動
  • 対象のページにリクエスト (fetch) があったときにキャッシュしたページをレスポンスとして返却

になります
ポイントですがまずキャッシュするページは cache.addAll に配列してパスを指定します
今回であれば HTML だけなので /sw_test だけで OK です
感が良ければここで気づくと思いますが CSS や JS も必要なページの場合はそれらもキャッシュしなければなりません
例えば http://localhost:9292/js/custom.js という JavaScript が必要な場合は /js/custom.js を配列に追加してください

activatefetch のイベントに関してはとりあえずそのまま使えば OK です

動作確認

では動作確認してみましょう
ちなみに Chrome で確認する場合は開発ツールの「Application」->「Service Workers」で登録した Service Worker の一覧や現在の状態を確認することができます
chrome://serviceworker-internals/ に Chrome でアクセスしても登録済みの Service Worker の一覧を確認することができます

まず普通にページアクセスします
すると Service Worker の登録が行われます
かつ今回の場合であればページのキャッシュも同時に行われています
service_worker1.gif

次にオフラインにして確認してみましょう
先程の Chrome 開発ツールのところに「Offline」ボタンがあるのでこれを使って擬似的にオフライン状態を再現します
ちなみに本当にオフラインかどうか一度 Youtube にアクセスを試みています
service_worker2.gif

こんな感じでキャッシュしたページであればアクセスしてもエラーのページとはならないのがわかると思います

最後に

噂の Service Worker に入門してみました
今回はかなり基本的な機能しか試していません
Service Worker を使えばブラウザプッシュなどもできるようになります

使っていてポイントだなと感じたのはキャッシュするページの量が多いと大変だなと思いました
最近だと WebPack や browserify などを使って 1 つのファイルにまとめることができるのでそういった仕組みを使うと相性が良いかと思います
また、どうしても外部のサイトの JS を参照しなければいけない場合にはそれえらを外す必要があります
例えば Google Analytics ですが解析のための JavaScript コードが入っていると Service Worker がエラーを吐き続けてしまいます
Google Analytics に限って言えば解析のためのコードなのでページ自体は動作すると思いますがエラーが出続けてしまうというのが気になるところです

Service Worker 用の JavaScript を用意するだけで簡単に対応できるのでやっておいて損はないような気がします
というのもオフラインキャッシュがすごいというよりかは PWA 対応できるのでスマホアプリ化できると考えると損はないかなと思います
ただ、冒頭簡単に説明しましたが https が必須なので注意が必要です

参考サイト

0 件のコメント:

コメントを投稿