シンプルなPWAサンプルここに置いておきますね

# PWAってすごそう！
PWA (Progressive Web Apps) とかいうやつに対応したら JavaScript でスマホアプリみたいなの作れるんだってヤッター！
と喜んでいたら・・。

- [はじめてのプログレッシブ ウェブアプリ - Google Developers](https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/?hl=ja)

# PWAってむずかしそう！
**なんか適当にPWA用のJSONファイルとかをサクっと置いとけばよしなに対応してくれるんでしょ** って思ってちょちょーいとサンプルコードをググってたら、みなさん丁寧にしっかり解説しすぎてて、とりあえず動かそうとしてた私にはなんだかムズカシイと感じました。

# 必要最低限でうごくシンプルなやつちょーだい！
ということで、細かい説明とか外部サービスとか `npm` とか余計な技術に触れずに、とにかく何にも依存しないクリーンなHTML/JS/CSSで短いPWAサンプルコードがあったら理解が早いし便利かなーって思って用意しました。実際の開発で必要なものがあればその都度調べてこれに毛を生やすといいかもです。（でも上記のGoogleさんのサイトは一通り読んでおいたほうが良さそうです）

ソースはGitHubに上がってます。主要ファイルの簡単な解説を後述しておきますが、シンプルなのでソースコード見てるだけでもなんとなくわかるかと思います。

- PWAサンプルアプリ ソースコード - GitHub  
  [https://github.com/kazaoki/pwa](https://github.com/kazaoki/pwa)

## PWAサンプルアプリ動作
GitHubPagesで公開してますのでこちらから実際の動きが確認できます。（以下、Android7.1＋Chrome64でのキャプチャです）
https://kazaoki.github.io/pwa/
<img src="https://qiita-image-store.s3.amazonaws.com/0/104199/a99b7529-e8f1-fb26-cd0b-8a237baa3c72.png" width="50%">

ここまではまぁ、普通のSPAですね。ブラウザ枠も出てます。
次に、**５分以上置いてもう一度アクセスする**と、ホーム画面に追加するかどうかの "バナー" と呼ばれるポップが下の方に出てきます。PWA特有のルールですね。Google Developers にバナー出現条件が記載されていますので確認しておきましょう。（なかなか出なくて焦るかもです）

- [ウェブアプリのインストール バナー - Google Developers](https://developers.google.com/web/fundamentals/app-install-banners/?hl=ja)

あ、残念ながらiOSはまだPWA未対応のようです（2018.3.8現在）ので、Android端末を買ってきてください。😜

<img src="https://qiita-image-store.s3.amazonaws.com/0/104199/88b41bf7-af81-a757-7834-b1e023e51508.png" width="50%">

「ホーム画面に追加」をタップすると、ホームにアイコンが作成されます。
これだけならブックマークとそう変わらないのですが、アプリ一覧に入ってきたり（！）、起動するとブラウザの枠がないためネイティブっぽくなっててワクワクします。
以下、実際にホーム画面に追加したアイコンから起動したPWAサンプルアプリのキャプチャです。アプリ領域がフルで使えてるのがわかるかと思います。

<img src="https://qiita-image-store.s3.amazonaws.com/0/104199/47671819-c982-6334-0146-8817cc36c949.png" width="50%">

# ざっと解説

ディレクトリ構造はGitHubの方を確認してもらうことにして、ここでは主要な３ファイルについてのみざっと説明します。

- `index.html`
- `manifest.json`
- `sw.js`

## index.html
いわゆるエントリポイントです。アプリが起動するとこのページが表示されますので、このファイルから実際にSPAとして動かすJSをロードして実行してあげましょう。（※今回ロードしてる `drawer.js` は線を描くプログラムで、本稿と関係ないため割愛してます）
また、このファイルで `manifest.json` や `sw.js` ファイルも指定しています。`sw.js` は、ServiceWorkerへの登録という形で指定します。

```html:index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="manifest" href="manifest.json">
<title>PWA Sample</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<canvas id="stage"></canvas>
<script src="drawer.js"></script>
<script>
// ServiceWorker登録：https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ja
if ('serviceWorker' in navigator) {
	navigator.serviceWorker.register('sw.js').then(function(registration) {
		console.log('ServiceWorker registration successful with scope: ', registration.scope);
	}).catch(function(err) {
		console.log('ServiceWorker registration failed: ', err);
	});
}
</script>
</body>
</html>
```

## manifest.json
PWAとして振る舞うための設定情報を記述しておきます。
`start_url` プロパティを変更してエントリポイントを `index.html` 以外にすることも可能です。
他にもいろんなプロパティがあるので、以下から確認しておきましょう。

- [ウェブアプリ マニフェスト - Google Developers](https://developers.google.com/web/fundamentals/web-app-manifest/?hl=ja)

```json:manifest.json
{
	"short_name": "PWAサンプル",
	"name": "PWAサンプルアプリ",
	"display": "standalone",
	"start_url": "index.html",
	"icons": [
		{
			"src": "images/app-icon-192.png",
			"sizes": "192x192",
			"type": "image/png"
		}
	]
}
```

## sw.js
ServiceWorkerの処理を書くところです。今回はキャッシュファイルのインストールとロードの部分が書いてあります。ファイルがキャッシュされている場合、オフラインでもアプリを動かす事が可能になります。
他にもこのファイルに色々（PUSH通信だの今後追加されるかもしれないジオフェンシングだの）処理を追加して、ServiceWorkerとしてがんばってもらう形になります。

```js:sw.js

// ServiceWorker処理：https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ja

// キャッシュ名とキャッシュファイルの指定
var CACHE_NAME = 'pwa-sample-caches';
var urlsToCache = [
	'/pwa/',
	'/pwa/css/style.css',
	'/pwa/drawer.js'
];

// インストール処理
self.addEventListener('install', function(event) {
	event.waitUntil(
		caches
			.open(CACHE_NAME)
			.then(function(cache) {
				return cache.addAll(urlsToCache);
			})
	);
});

// リソースフェッチ時のキャッシュロード処理
self.addEventListener('fetch', function(event) {
	event.respondWith(
		caches
			.match(event.request)
			.then(function(response) {
				return response ? response : fetch(event.request);
			})
	);
});
```

# 最後に
PWAの公開URLはSSLが必須ですので、配信サーバはよく検討しておきましょう。