webpack入門_Progressive Web Application

Progressive Web Application

webpackの公式ドキュメントのProgressive Web Applicationを見ていきたいと思います。

まずPWA(Progressive Web Application)ですが、これはWEBアプリをネイティブアプリのように動作させる技術のようで以下のドキュメントを見れば大体わかるのかと思います。
https://developers.google.com/web/progressive-web-apps/
https://speakerdeck.com/nazonohito51/pwafalsesanpuruapuriwozuo-tutemita

既存のブラウザキャッシュとどう違うのかよく分からなかったのですが、以下のstack over flowを見てみるとPWAは組み込みのブラウザキャッシュよりも詳細な制御が可能で、読み込み時間をより短くすることができるといった感じのようです。ただ現在Progressive Web Applicationに対応しているブラウザはChromeFirefoxのみのようなので注意が必要です。
https://stackoverflow.com/questions/35190699/whats-the-difference-between-using-the-service-worker-cache-api-and-regular-bro

PWA設定

それではwebpackのプロジェクトをPWAに対応させたいと思います。
まず、以下のコマンドでworkbox-webpack-pluginをインストールします。

npm install --save-dev workbox-webpack-plugin

それからwebpackの設定でworkbox-webpack-pluginを有効にするため、pluginsにWorkboxPlugin.GenerateSWを追加します。

<!-- 省略 -->
const WorkboxPlugin = require('workbox-webpack-plugin');

module.exports = {
<!-- 省略 -->
  plugins: [
    new WorkboxPlugin.GenerateSW({
      // these options encourage the ServiceWorkers to get in there fast
      // and not allow any straggling "old" SWs to hang around
      clientsClaim: true,
      skipWaiting: true
    })
<!-- 省略 -->

それからこの状態でビルドをするとコンソールに以下のような出力があります。

Asset       Size  Chunks             Chunk Names
app.bundle.js   1.83 KiB       0  [emitted]  app
vendors~app.bundle.js   69.5 KiB       1  [emitted]  vendors~app
index.html  234 bytes          [emitted]
precache-manifest.ef740440ea3c540d2a9342f21e33ab31.js  274 bytes          [emitted]
service-worker.js  955 bytes          [emitted]
Entrypoint app = vendors~app.bundle.js app.bundle.js

service-worker.jsprecache-manifest.ef740440ea3c540d2a9342f21e33ab31.js が増えていたらPWAの設定が有効になっています。

試しにservice-worker.jsを見てみると以下のようになり、importScriptsでprecache-manifest.ef740440ea3c540d2a9342f21e33ab31.jsを参照していることが確認できます。

importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.4.1/workbox-sw.js");

importScripts(
  "precache-manifest.ef740440ea3c540d2a9342f21e33ab31.js"
);

workbox.skipWaiting();
workbox.clientsClaim();

/**
 * The workboxSW.precacheAndRoute() method efficiently caches and responds to
 * requests for URLs in the manifest.
 * See https://goo.gl/S9QRab
 */
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

次にprecache-manifest.ef740440ea3c540d2a9342f21e33ab31.jsを確認してみると以下のようにjsファイルのrevisionとurlを管理しており、これによりキャッシュ対象が決まっていることが想像できます。

self.__precacheManifest = [
  {
    "revision": "685e6afb118142fa5a61",
    "url": "vendors~app.bundle.js"
  },
  {
    "revision": "a374501106008a1687b12f7e5535aaa3",
    "url": "index.html"
  },
  {
    "revision": "29f3ff959afdf304a73d",
    "url": "app.bundle.js"
  }
];

動作確認

次にPWAの動作確認をしたいと思うのですが、serviceworkerによりバンドルファイルなどが読み込まれることが確認できれば良いので以下のような手順にしたいと思います。
- http-serverをインストール
- キャッシュさせるためhttp-serverを起動しlocalhostにアクセス
- http-serverを停止してから再度localhostにアクセス

ではまず以下のコマンドでhttp-serverをインストールします。

npm install --save-dev http-server

それから、package.jsonのscriptsを修正します。

<!-- 省略 -->
"scripts": {
  "build": "webpack --config webpack.prod.js",
  "start": "webpack-dev-server --open --config webpack.dev.js",
  "http": "http-server dist",
  "test": "echo \"Error: no test specified\" && exit 1"
},
<!-- 省略 -->

次にhttp-serverを起動しブラウザでhttp://localhost:8080/にアクセスします。

npm run http

ブラウザでの表示が確認できたら、次にhttp-serverを停止しブラウザのページをリロードします。この時開発者ツールのネットワークでバンドルファイル等がServiceWorkerから読み込まれていることが確認できます。 f:id:steavevaivai:20180729065300p:plain

サービスワーカーのキャッシュを消したい場合はコンソールから以下を実行します。

navigator.serviceWorker.getRegistrations().then(function(registrations) {
    for(let registration of registrations) {
        registration.unregister();
    }
});
caches.keys().then(function(keys) {
    var promises = [];
    keys.forEach(function(cacheName) {
        if (cacheName) {
            promises.push(caches.delete(cacheName));
        }
    });
});