PWAのキャッシュ戦略

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

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

## Get Set Up
とりあえず clone しておきましょう！

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

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

<img width="257" alt="スクリーンショット 2019-11-11 0.28.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/47849a21-4f3d-3710-42b9-3c015e343237.png">

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

## npmがない人

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

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

https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09

<img width="648" alt="スクリーンショット 2019-11-11 0.39.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/d3bd9105-9e4a-4d16-6123-2c8e363ac0f6.png">

いい感じスネ。

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

nodebrew のバージョンを確認します
<img width="321" alt="スクリーンショット 2019-11-11 0.43.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/61f05e32-dd8b-964c-3cfa-1ade2424c6fa.png">

v7.1.0はインストールされていませんを確認します
<img width="404" alt="スクリーンショット 2019-11-11 0.45.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/7f477f0a-53a6-1c42-796d-222da50d3171.png">

v7.1.0をuseしてｷﾀ━━━(ﾟ∀ﾟ)━━━!!
<img width="182" alt="スクリーンショット 2019-11-11 0.55.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/afff74f3-8ecd-2101-1057-a5165855b727.png">

## npm install する

やっとnpm install できますね！

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

```bash
cd workbox-lab/project
```

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

<img width="1245" alt="スクリーンショット 2019-11-11 0.58.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/706f58eb-24d6-3920-089c-b9e663fca552.png">

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

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

```bash
npm install --global workbox-cli
```

すると下記のようにまたインストールされます
<img width="1242" alt="スクリーンショット 2019-11-11 1.03.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/b3f0e49e-3399-2b12-8c2b-48319b988d73.png">

## ビルドアンドスタート
`npm build` と `npm start`しましょう

```bash
npm build
```

```bash
npm start
```

## ページ確認
下記URLをブラウザでリクエストしましょう。
`http://localhost:8081/`

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

<img width="1680" alt="スクリーンショット 2019-11-11 1.08.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/547ad97d-1f7a-4c79-f39b-e888907f6ef8.png">

OKですね〜！

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

```html
<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`で開発者モードにしましょう！

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

<img width="1677" alt="screen1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/8ce908b9-f36c-1569-762a-d71420296916.png">

## ServiceWorkerを作成する

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

```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モジュール一覧
https://developers.google.com/web/tools/workbox/modules/

### キャッシュ
`workbox.precaching.precacheAndRoute([]);`

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

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

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

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

### manifestをService Workerに注入する

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

```bash
workbox wizard --injectManifest
```

すると

<img width="1245" alt="スクリーンショット 2019-11-11 1.57.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/2bd251bd-e390-7295-de81-ee750a993dd5.png">

上記のようにいろいろ聞かれるので
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は次のようになります。

```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`を保存したら下記のコマンドを実行しましょう！

```bash
npm run build
```

### 新しいServiceWorkerを登録する

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

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

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

1. `Clear storage`
2. `Clear site data`


<img width="1677" alt="evi3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/40666e03-0ef8-fc7a-da3e-a42b53b09e62.png">

`sw.js`が`ServiceWorker`として登録されているか確認する

<img width="858" alt="スクリーンショット 2019-11-11 2.14.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164151/299aeea5-b732-2755-91c3-21688d613007.png">

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

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

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

```json
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