はじめに
以前から気になっていたPWAについて、導入するまでに最低限必要な3つのステップについて書きたいと思います。
この記事のゴールは、PWAでオフラインでもとりあえず動作するページを作成するまでです。
PWAとは
PWA(Progressive Web Apps)は、Googleが推進するWeb上でネイティブアプリ同等のUXを実現できる技術です。
PWAの機能にはプッシュ通知、ホーム画面に追加、コンテンツキャッシュなどの機能があり、これらの機能を使用することでオフラインで動作するWebアプリを作成できたり、ネイティブアプリのようにユーザの端末にアプリをインストールすることができます。
アプリをインストールする際、ネイティブアプリのようにアプリストアを経由する必要はありません。
作成したデモ
●リポジトリ
https://github.com/yshrkn/pwa-test
対応ブラウザ
最新ブラウザであれば概ね動くようです。
Safari、iOS(Edgeは未確認)は一部機能に対応していないようです。
iOS12で試してみましたが、「ホーム画面に追加」は動きませんでした。
iOSが対応している詳細な機能については、下記記事にまとまっています。
PWAを導入するための3ステップ
PWAを導入するには下記3つを対応する必要があります。
- HTTPS対応
- マニフェストの作成・読み込み
- Service Workerの作成・読み込み
1. HTTPS対応
PWAに対応するためにはService Workerが必要ですが、Service WorkerはHTTPSのサイト上でのみ動作します。
まずはHTTPS環境を用意する必要があります。
今回はお手軽にテストするために、HTTPSに対応しているGithub Pagesを使用しました。
Service Workerについてざっくり理解するには、下記ページが分かりやすいです。
2.マニフェストの作成・読み込み
PWAの基本的な設定を記述するマニフェストと呼ばれるJSONファイルを用意する必要があります。
ファイル名は任意で問題ありません。一般的にはmanifest.jsonが使用されます。
マニフェストファイルの主な設定項目
| プロパティ | 説明 | 
|---|---|
| name | サイトがユーザに表示される時に表示されるテキスト。 | 
| short_name | ユーザーホーム画面で表示されるテキスト。 | 
| start_url | ホーム画面に追加された際、アプリを起動して最初に呼び出されるページへのパス。 | 
| theme_color | アプリケーションの既定のテーマ色。タスク切り替えの時に使用される場合がある。 | 
| background_color | ホーム画面から起動した際にスプラッシュ画面の背景色として使用される。 | 
| icons | アプリのアイコンに使用する画像ファイルを配列で設定。 | 
| display | アプリの起動方法を設定する。 standalone を指定するとネイティブアプリのようにURLバーなどが取り除かれ独立して起動。 | 
より詳しい設定項目については下記記事も参照してください。
マニフェストの作成
では実際にルートにmanifest.jsonを追加します。
{
  "name": "PWA Test",
  "short_name": "PWA",
  "theme_color": "#2196f3",
  "background_color": "#2196f3",
  "display": "standalone",
  "start_url": "./index.html",
  "icons": [
    {
      "src": "./images/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ]
}
マニフェストの読み込み
PWA対象の全てのHTMLのheadタグで、作成したmanifest.jsonを読み込みます。
<link rel="manifest" href="./manifest.json">
3. Service Workerの作成・読み込み
Service Workerの作成
Service Workerを作成します。
Service Workerのファイル名やファイルの置き場所は任意で構いません。
ファイルの置き場所によってService Workerがキャッチできるイベントのスコープが決まります。
例えば、/news配下のみをPWA対応する場合、/news直下にService Workerのファイルを配置することで/newsフォルダ配下のみをPWAに対応できます。
// Cache name
const CACHE_NAME = 'pwa-sample-caches-v1';
// Cache targets
const urlsToCache = [
  './',
  './index.html',
  './pages/a.html',
  './pages/b.html',
  './pages/c.html',
  './css/style.css',
  './images/a.jpg',
  './images/b.jpg',
  './images/c.jpg',
];
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches
      .open(CACHE_NAME)
      .then((cache) => {
        return cache.addAll(urlsToCache);
      })
  );
});
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches
      .match(event.request)
      .then((response) => {
        return response ? response : fetch(event.request);
      })
  );
});
ざっくりとプログラムの内容を記述します。
細かな部分の詳細な解説は下記ページをご参照ください。
まずはじめにオフラインで動作させるために、キャッシュ名をCACHE_NAMEに、キャッシュ対象ファイルをurlsToCacheに指定しています。
Service Workerは正常に登録されるとinstallイベントが走るので、installイベント内でcachesをオープンさせ、すべてのキャッシュ対象ファイルがキャッシュされるのを待機します。
キャッシュが成功したらキャッシュを追加、1ファイルでもキャッシュに失敗したらキャッシュは失敗します。
fetchイベントはService Workerがインストール済みの状態でページ移動すると発生します。
fetchイベントが発生したとき、リクエストされたファイルがキャッシュの中にあれば該当するキャッシュを返し、なければリクエストされたファイルをfetchに渡してネットワークから取得した結果を返しています。
✳︎キャッシュを更新するコードは入っていないので、別途書いてあげる必要があります。
Service Workerの読み込み
作成したsw.jsをHTML側で読み込みます。
Service Worker対応ブラウザであればsw.jsを登録しています。
<script>
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js').then(registration => {
      console.log('ServiceWorker registration successful.');
    }).catch(err => {
      console.log('ServiceWorker registration failed.');
    });
  }
</script>
動作確認
「ホーム画面に追加」と、機内モードにしたオフライン状態でもしっかり閲覧できました!
開発者ツールでファイルを確認する
Chromeの開発者ツールの「Application」タブの中に「Manifest」や「Service Worker」の状態、キャッシュの有無が確認できます。
最後に
思ったよりもPWAの導入が容易にできて驚きました。
ちゃんとしたオフライン対応をするには、キャッシュの更新処理を書く必要があったりするので、これからもっと深く学んでみようと思います。
今回は触れませんでしたが、PWAにはプッシュ通知などの魅力的な機能がたくさんあるので、それらを使用してなにかアプリを作ってみたいと思います。


