#webaudio
#serviceworker
#workbox

WorkboxでWeb Audioのアプリをオフラインで使えるようにしてみる

この記事は WebAudio/WebMIDI API Advent Calendar 2017 Advent Calendar 2017 の21日目です。

TL;DR

またもや、Web Audio/MIDIとあんまり関係ない記事で恐縮ですが・・・
楽器系のアプリってオンラインで使う必要がないのが多いですよね?とは言っても「ウェブアプリってオフラインで動作できるの?」みたいな疑問もあると思います。今回はそこをWorkboxというオフラインでウェブアプリを動かす為のライブラリでありビルドツールを使って細かい説明は抜きにしてチャチャッとオフライン化を試してみます。
WorkboxはServiceWorkerを使うことでウェブアプリがオフラインでも動くようにするための助けをしているのです。

ServiceWorkerとは

ウェブページの表示、処理とは独立して動作させることのできる、開発者がJavaScriptで記述することが可能なバックグラウンドで処理を走らせることが可能な機能です。
動作する場所は、以前はブラウザがらインターネットに直接接続をしていたのですが、この間に入ることで、オフライン状態での処理だったり、ブラウザ動作していない状態でもメッセージ(Push Notification)を受けることを可能にしています。
こんな感じです。「プロキシサーバーみたいな」と説明されることも多いです。

Screen Shot 2017-12-20 at 1.28.37 AM.png

ちなみに、ServiceWorkerはHTTPSのサーバのコンテンツにのみ有効です。個人で試す場合は、GitHub Pagesを使うのがもっとも手っ取り早いでしょう。

Workbox

ここで登場するのがWorkbox。ServiceWorkerってとても便利だから、もっと使ってもらうために簡単に導入できる、また最適なコードを吐き出すツールをGoogleさんが作った、という感じです。

Service Workerでオフライン体験

下準備

この説明の画面が消えてしまっては困りますので、プライベートブラウジングモード(Incognito Window)を使いましょう。設定だったり、Cookieが閉じた世界になり通常のChromeのとは別扱いになります。またプライベートブラウジングモードの画面を閉じると、そこでの閲覧履歴、キャッシュは一切ブラザには残りません。(日本語モードだとちょっと見栄えが違うかもしれませんね・・・)
Screen Shot 2017-12-20 at 12.58.48 PM.png

ユーザとして体験してみる

Get Coin!というアプリをつくりました。アクセスしてみると、こんな画面が表示されます。ドルマークのコインをクリックすると、コインの音が鳴り(Web Audio😁)、コインがクルリと回転するだけの単純なアプリです。動作させてみましょう。
Screen Shot 2017-12-20 at 1.40.00 AM.png

さて、ここからはホントにオフラインで動作しているのか確認作業に入ります。macOSのChromeで説明しますね。
まずはDeveloper Tools(DevTools)を表示して下準備を始めます。DevToolsはメニューから[View]-[Developer]-[Developer Tools]を選択すると、下の図の右側のような画面ブラウザの中、または別のウインドウに表示されるはずです。
次に赤文字の(1)「Application」のタブを開き、次に(2)「Service Workers」を選択してください。そうすると下の図のようになると思います。
Screen Shot 2017-12-20 at 1.46.26 AM.png

では早速オフラインにしまみましょう。(3)の「Offline」にチェックを入れてください。これでブラウザはオフラインになりました。Google.co.jpだったりYahoo.co.jpにこのタブでアクセスしてみてください。みんなの大好きなOffline Dinosauarに会えたことでしょう。
Screen Shot 2017-12-20 at 1.58.59 AM.png
この状態でもう一度Get Coin!にアクセスしてみてください。不思議なことにOffline Dinosauarには会えなく、Get Coin!のアプリがオンラインのときと同様に動作したはずです。

ということで、めでたくウェブアプリでもオフラインで動作することが体験できました!

開発者として体験してみる

(この先を体験するにはNode.jsがインストールされている必要があります。Node.jsのVersionは9.3.0を使っています。またTerminalをご用意ください。)

コードをCloneする

体験する為にコードを用意しましたのでCloneしてください。[GitHub]

$ git clone https://github.com/ryoyakawai/getcoin.git;

npmパッケージのインストール

続いて、動作に必要なパッケージをnpmを使ってインストールします。

$ cd getcoin;
$ npm install;

オンラインのみで動作するモードでビルド

そして、オンラインのみで動作するモードでビルドします。

$ npm run build:nosw;

ウェブサーバを起動して動作の確認

ウェブサーバを起動します。

$ npm run start;

プライベートモードのChromeでhttp://localhost:8081にアクセスしてみてください。Get Coinが無事に表示されたと思います。
続いて、オフラインでは動かないことを確認。
Terminal画面に戻って、Ctrl + cとかでウェブサーバを停止し、ブラウザを更新すると、、、Get Coinは動作しません。

これで、オフラインでは動かないことが確認できました。
続いてオフラインでも動作するモードでビルドします。

オフラインでも動作するモードでビルド

$ npm run build:sw;

すると3つの質問がWorkboxからされます。オフライン動作をさせる為に必要な情報を収集する目的の質問です。(「workbox-cliは動かなくなるよ」という警告を気に留めておきましょう・・・)
1つ目はsrcを選択してください。
(ビルド前のソースのありかを問われています)

$ npm run build:sw;

> coin@1.0.0 build:sw /Users/kawai/Y_UX/Sources/tmp/coin.master/getcoin
> workbox-cli generate:sw && copyfiles -e '**/sw.js' -u 1 src/*.{html,js,css,json,png} build

Please run the command line tool as 'workbox' instead of 'workbox-cli'.
'workbox-cli' will stop working in the next major release.
(See: https://github.com/GoogleChrome/workbox/issues/730)
? What is the root of your web app? (Use arrow keys)
  build 
❯ src 
  ──────────────
  Manually Enter Path 

2つ目の質問は何もせずにそのままEnterキーで次に進みます。
(どのファイルタイプをキャッシュするか、すなわちオフィラインで使いたいか、を問われています。ファイルタイプで選択するの?という疑問はさておき・・・)

$ npm run build:sw;

> coin@1.0.0 build:sw /Users/kawai/Y_UX/Sources/tmp/coin.master/getcoin
> workbox-cli generate:sw && copyfiles -e '**/sw.js' -u 1 src/*.{html,js,css,json,png} build

Please run the command line tool as 'workbox' instead of 'workbox-cli'.
'workbox-cli' will stop working in the next major release.
(See: https://github.com/GoogleChrome/workbox/issues/730)
? What is the root of your web app? src
? Which file types would you like to cache? (Press <space> to select, <a> to toggle all, <i> to inverse selection)
❯◉ css
 ◉ js
 ◉ png
 ◉ html
 ◉ json

3つ目の質問も、何もせずにそのままEnterキーで次に進みます。

$ npm run build:sw;

> coin@1.0.0 build:sw /Users/kawai/Y_UX/Sources/tmp/coin.master/getcoin
> workbox-cli generate:sw && copyfiles -e '**/sw.js' -u 1 src/*.{html,js,css,json,png} build

Please run the command line tool as 'workbox' instead of 'workbox-cli'.
'workbox-cli' will stop working in the next major release.
(See: https://github.com/GoogleChrome/workbox/issues/730)
? What is the root of your web app? src
? Which file types would you like to cache? (Press <space> to select, <a> to toggle all, <i> to inverse selection)css, js, png, html, json
? What should the path of your new service worker file be (i.e. './build/sw.js')? (build/sw.js) 

サイトに、質問の答えを保存するかを問われます。保存すると次回からはこれらの質問には答えなくて良くなりますが、ここでは保存しないnを選択します。

$ npm run build:sw;

> coin@1.0.0 build:sw /Users/kawai/Y_UX/Sources/tmp/coin.master/getcoin
> workbox-cli generate:sw && copyfiles -e '**/sw.js' -u 1 src/*.{html,js,css,json,png} build

Please run the command line tool as 'workbox' instead of 'workbox-cli'.
'workbox-cli' will stop working in the next major release.
(See: https://github.com/GoogleChrome/workbox/issues/730)
? What is the root of your web app? src
? Which file types would you like to cache? (Press <space> to select, <a> to toggle all, <i> to inverse selection)css, js, png, html, json
? What should the path of your new service worker file be (i.e. './build/sw.js')? build/sw.js
? Last Question - Would you like to save these settings to a config file? (Y/n) n

以上で準備は完了です。

ウェブサーバを起動して動作の確認

ウェブサーバを起動し、先ほどと同様にプライベートブラウジングモードのウィンドウでhttp://localhost:8081を表示し、Get Coinの動作を確認してみましょう。

$ npm run start

> coin@1.0.0 start /Users/kawai/Y_UX/Sources/tmp/coin.master/getcoin
> node server.js

App listening at http://localhost:8081

動作したはずです。では、オフラインで動くか試してみます。

オフラインでも動作するか確認

こちらも先程同様に、Terminal画面に戻って、Ctrl + cとかでウェブサーバを停止し、ブラウザを更新すると先程は動かなかったGet Coinが動作・・・・しました!
これで、自分の環境でもオフラインのウェブアプリが開発できることが分かりました。

簡単な説明

ビルド前のソースのあるsrcディレクトリ内のファイルと、オフラインでも動作するようにビルドした後のbuildディレクトリの比較をしてみると以下の3つがbuildディレクトリ内にしかないことが分かります。

  • sw.js
  • workbox-sw.prod.v2.1.2.js
  • workbox-sw.prod.v2.1.2.js.map

sw.jsが怪しいですね。残り2つはWorkboxのライブラリであることは想像がつきます。sw.jsの中身を見てみます。

const fileManifest = [
  {
    "url": "coin.css",
    "revision": "50717a84d6e367e4f08ac172945a3892"
  },
  {
    "url": "coin.js",
    "revision": "aed0df59696b46148080cd379d320460"
  },
  {
    "url": "coinicon_144x144.png",
    "revision": "3edc5d3a4321edce9a67bd5fab48f079"
  },
  {
    "url": "coinicon_200x200.png",
    "revision": "de2f6354cc4cf6943d8bc2557cab3dd6"
  },
  {
    "url": "index.html",
    "revision": "0cf5edd8967448b09d44c2e744c98f7c"
  },
  {
    "url": "main.css",
    "revision": "0cbc865c7c504e0117b0c77b8613e8a6"
  },
  {
    "url": "manifest.json",
    "revision": "cc04baae268df20734344d542b7bdfb6"
  }
];

const workboxSW = new self.WorkboxSW();
workboxSW.precache(fileManifest);

urlrevisionを持ったObjectの配列として書かれていました。これは、どのファイルをキャッシュするかのがurlで、またどのVersionとしてキャッシュするかがrevisionで書かれています。このrevisionは、更新したファイルを動作させてときにキャッシュし直しが必要かどうかの管理をしていますので、重要です。ここが書き換えられないと、ウェブサーバ側でファイルが更新されても、ブラウザに反映されない、ということが起こることになります。
sw.jsは、Workboxからの質問に答えることで生成されました。ウェブサーバ側でファイルが更新したときは、Workboxからの質問に答えて再生成してください。(他にも方法あるかも?)

ということでウェブアプリをオフライン化することが簡単にできました。

自分で作ってみる

すぐに始められるようにgit cloneしたソースにtemplate以下に雛形を作りました。ここの下にウェブアプリを作り「オフラインでも動作するモードでビルド 」からの手順を踏むとオフラインで動作するアプリを作ることが可能です。是非試してみてくださいね!

まとめ

ウェブアプリのオフライン化が可能であること、また比較的に簡単に実現できることを確認してもらえたと思います。オンラインである必要が特にないウェブアプリでは使うことをオススメします。がんばって開発したアプリケーションを多くの人に使ってもらう為にも是非導入してみてください!

補足 (2017/12/21 利用可能なブラウザについて説明追記)

2017年12月21日現在の利用可能なブラウザについては以下の表の通りです。 現状はこうなっています。
Screen Shot 2017-12-20 at 11.02.28 PM.png