PWAのキャッシュ戦略


はじめまして、おはこんばんちは。hiraokです。
普段はAndroidエンジニアとして粛々と活動してます。
最近自分のきゃりあについて悩みすぎてハゲそうなのでGoogleのCodelabsでPWA始めてみました。
https://codelabs.developers.google.com/codelabs/workbox-lab/index.html

これを見てこの人に比べたらわたし、おれ大丈夫だなって思っていただけたら幸いです。

Get Set Up

とりあえず clone しておきましょう!

git clone https://github.com/googlecodelabs/workbox-lab.git

プロジェクトに依存するパッケージインストールしてサーバースタートしてくれや

まじかーーーーーーーーーーーーい

npmがない人

npmはnode.jsインストールすると自動的に入ります。

下記がすごい役に立ちました。ありがとうございます。

いい感じスネ。

nodebrewインストールできました

上記のインストール手順通り進むとnodebrewがインストールできた状態まで行けました。

nodebrew のバージョンを確認します

v7.1.0はインストールされていませんを確認します

v7.1.0をuseしてキタ━━━(゚∀゚)━━━!!

npm install する

やっとnpm install できますね!

workbox-lab/projectに移動しましょう

cd workbox-lab/project

移動したらnpm installしましょう

なんか上記みたいになったらOKです。

OKになったら下記コマンドを打ちましょう

npm install --global workbox-cli

すると下記のようにまたインストールされます

ビルドアンドスタート

npm buildnpm startしましょう

npm build
npm start

ページ確認

下記URLをブラウザでリクエストしましょう。
http://localhost:8081/

すると下記のようなページがでてきます。

OKですね〜!

パッケージ構成

サンプルプロジェクトのworkbox-lab/project/src/index.htmlにはどうやら空のserviceWorkerなるものがあるらしいです。

<script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js')
          .then(registration => {
            console.log(`Service Worker registered! Scope: ${registration.scope}`);
          })
          .catch(err => {
            console.log(`Service Worker registration failed: ${err}`);
          });
      });
    }
  </script>

ではhttp://localhost:8081/をもう一度開きましょう。開いていたらごめんな。

開いたら cmd + opt + jで開発者モードにしましょう!

すると、下記のような画面になります。

ServiceWorkerを作成する

上記のような状態で確認できたところでServiceWorkerなるものをsrc/js配下に作成していきましょう
ファイル名はsw.jsにしましょう!

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.5.0/workbox-sw.js');
if (workbox) {
  console.log(`Yay! Workbox is loaded 🎉`);
  workbox.precaching.precacheAndRoute([]);
} else {
  console.log(`Boo! Workbox didn't load 😬`);
}

impoerScriptsというfunctionでCDNからworkbox-sw.jsというライブラリをインポートしているみたいです。
workbox-sw.jsがロードされることによってServiceWorker(このファイル)がworkboxモジュールへアクセスすることを許可することになります。

workboxモジュール一覧

キャッシュ

workbox.precaching.precacheAndRoute([]);

この一文はmanifestと言われるリビジョンハッシュを含むファイルURLの一覧を取得し、ServiceWorkerインストール時にキャッシュするらしい※1

リソースはキャッシュ優先になっており、デフォルトでキャッシュされたリソースが優先的に選択されるようになるみたいです。

workbox-cli

workbox-cliなるツールを使用してmanifestを自動で作成するとざっくり超ざっくり下記のように便利なことになるらしい。(すみません。。ここらへんよくわからなくて曖昧です)

  1. アプリのファイルを更新するたびにmanifestを手動で更新する必要がなくなる。
  2. リビジョンハッシュが自動で追加されるのでファイルのキャッシュを常に最新の状態に保つことができる(リビジョンハッシュにより最新の状態を追跡することが可能になる)マニフェストに存在しないキャッシュファイルを削除することでユーザーデバイスのデータ量を最小限に抑えることができる

manifestをService Workerに注入する

下記コマンドを別セッションで実行しましょう

workbox wizard --injectManifest

すると

上記のようにいろいろ聞かれるので
1. build/
2. css
3. return
4. return

で設定しましょう。
するとworkbox-config.jsというのが作成されます。こいつがService Workerの生成に使用する構成ファイルとなります。
構成ファイルは、ファイルの検索場所(globDirectory)、プリキャッシュするファイル(globPatterns)、およびソースサービスワーカーと運用サービスワーカーのファイル名(それぞれswSrcとswDest)を指定します。また、この構成ファイルを直接変更して、事前キャッシュするファイルを変更することもできます。それについては後のステップで検討します。

workbox-cliツールの使用

package.jsonを開き、ビルドスクリプトを更新して、Workbox injectManifestコマンドを実行します。
更新されたpackage.jsonは次のようになります。


{
  "name": "workbox-lab",
  "version": "1.0.0",
  "description": "a lab for learning workbox",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "copy": "copyfiles -u 1 src/**/**/* src/**/* src/* build",
    "build": "npm run copy && workbox injectManifest workbox-config.js",
    "start": "node server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.3"
  },
  "devDependencies": {
    "copyfiles": "^1.2.0",
    "workbox-cli": "^3.5.0"
  }
}

上記のpackage.jsonを保存したら下記のコマンドを実行しましょう!

npm run build

新しいServiceWorkerを登録する

http://localhost:8081に戻りましょう。

そしてcmd+opt+jをして開発者モードにします。

下記で古いキャッシュを削除しましょう。

  1. Clear storage
  2. Clear site data

sw.jsServiceWorkerとして登録されているか確認する

Workbox injectManifestってなにものか

Workboxはsrc/sw.jsのコピーを作成し、manifestをそのファイルに注入し、プロダクションのServiceWorkerファイルとしてbuild/sw.jsを作成します。
今回、cssファイルをキャッシュするようにworkbox-config.jsを構成したため、プロダクションのServiceWorkeのmanifeststyle/main.cssがあります。
その結果、ServiceWorkerのインストール中にstyle/main.cssが事前にキャッシュされました。

これで、アプリを更新するたびに、npm run buildを実行してアプリを再構築し、サービスワーカーを更新できます。

workbox-config.jsを更新してみよう

src/workbox-config.jsを下記のように書き換えてnpm run buildしてみましょう

module.exports = {
  "globDirectory": "build/",
  "globPatterns": [
    "**/*.css",
    "index.html",
    "js/animation.js",
    "images/home/*.jpg",
    "images/icon/*.svg"
  ],
  "swSrc": "src/sw.js",
  "swDest": "build/sw.js",
  "globIgnores": [
    "../workbox-config.js"
  ]
};

アプリを更新し、ブラウザーで更新されたService Workerをアクティブにします。
Chrome DevToolsでは、[アプリケーション]タブに移動し、[サービスワーカー]をクリックしてから[skipWaiting]をクリックすることにより、新しいサービスワーカーをアクティブにできます。
開発者ツールで、globPatternsファイルがキャッシュ内にあることを確認します(新しい追加を確認するには、キャッシュを更新する必要がある場合があります)。

ウォッカグレープフルーツジュース割飲みつつ書いているのでnemasu