Progressive Web Apps (PWA) 学習者のメモ その1 Service Worker の設定
Progressive Web Apps (PWA) 学習者のメモ その1 Service Worker の設定:
PWAについて勉強中の人間(=自分)のためのメモです。
PWAについての理解がふわっとしていたので、おさらいし直した内容を記しました。
2019年2月時点のメモとなりますが、誤記などありましたらどうぞご指摘ください。
Google が提唱・推進しているアプリ
https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/?hl=ja
概念はGoogle の説明を参照するとして、仕様面で見ると
ウェブ技術を使っているという点で、Apache Cordova を利用したハイブリッドアプリに近い。
ただし、PWAはウェブ経由で配布可能であり、パッケージ化するにあたって Apache Cordova などのライブラリは必ずしも必要としない。
ブラウザによって各種APIの実装状況は異なるため、すべてのブラウザ環境、スマホ環境で使えるわけではない。
(2019年2月の段階)
https://developers.google.com/web/fundamentals/architecture/app-shell?hl=ja
PWAのコアにあたる。
特別な技術のような響きがあるが、「アプリが動く枠組み部分」「アプリ用テンプレート」と言った概念を言語化したもの。たとえば、下記のようなシンプルなhtmlでも「App Shell」になりうる。
<div id="main">のDOMに、各種情報をフェッチすれば、PWA の App Shell として成立する。
Google の記事内では、App Shell はコンパクトであるべき、と言っている。シンプルな Shell ファイルをPWAのコアとして設計し、コンテンツとApp Shell を分けたほうが良い、とするようだ。
(明確な定義がないため「どこまでがシンプルなのか」は、実装者の判断になりうる)
https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ja
ウェブページからの入力とは独立して、ブラウザのバックグラウンドで動作する。
プッシュ通知やバックグラウンド同期などを行う。
将来的にさらなる機能拡張が予定されている。
オフラインの状態でも何らかの形でアプリが動作するようサポートする機能が実装されている。
Promiseを多用するため、Promiseの概念・挙動を理解しておく必要がある。
Service Workerを利用するためには、明示的に有効化する必要がある。
下記はGoogle のチュートリアルに記載されている、Service Workerを有効化するサンプルコード。
Service Worker が利用可能かどうかの判定を行い、利用可能であれば サービスワーカーの挙動を定義したJSファイル(ここでは sw.js) を登録する。
Service Worker の振る舞いは、Service Worker 登録用のファイルにJavaScript のコードとして記述する必要がある。
PWAユーザーに対して通知を送れる機能。
ユーザーに通知を送るAPIとしては
の2つがある。PWAの世界で一般的に「プッシュ通知」について説明する場合、後者のPush APIを利用したものを指す。
Push APIを利用すると、アプリを利用中のユーザーに対してプッシュ通知を送ることができるが、通知用のサーバーが必要になる。また、秘密鍵と公開鍵を作成して、アプリ側に公開鍵をセットする必要がある。
プッシュ通知はサーバーが必要なことから、Firebase を利用した実装を見ることが多い。
(必ずしもFirebaseである必要はないが、Firebaseを使う実装が手っ取り早い)
Google のチュートリアルでは、Nodeを使ったテスト用のサーバーを紹介している。
Service Worker、Fetch API、Push API が動作するブラウザ が PWA対応ブラウザ、と言っても良さそう。
各ブラウザの Service Worker の対応状況は以下が参考になる。2016年頃と比べると、ずいぶん対応が進んでいる。
https://caniuse.com/#search=Service%20Workers
Fetch APIの対応状況は以下
https://caniuse.com/#search=Fetch%20api
Push API
https://caniuse.com/#search=push%20api
簡単なPWA対応アプリを作り、挙動を見てみる。
アプリの仕様は以下とする。
まずは、PWA対応をしていない、普通のウェブアプリの状態で作ってみた。
サンプルは以下。
https://newqiitapost.firebaseapp.com/v1/
コードは以下の通り。
index.html
JS(main.js)
cssは素のBootStrapをインクルード利用している。
スマートフォンにインストールしてアプリのように利用するためには
https://developers.google.com/web/fundamentals/web-app-manifest/?hl=ja
https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ja
manifst.jsonでは
これを踏まえて、manifest.jsonを作成。以下は例。
次に、Service Worker 登録用のJSを作成する。
Service Worker 登録用のファイルでは大まかに言って
先に作ったVer1のウェブアプリでは
index.html。head内で 「manifest.json」を読み込んでいる。
main.jsに、Service Worker の登録を行うスクリプトを追記する。
Service Worker インストール用のファイル sw.js
実際に動くサンプルはこちら。
https://newqiitapost.firebaseapp.com/v2/
このアプリをAndroidのスマホブラウザ(Chrome)で見ると、ホーム画面に登録するか (=インストールするか) を聞いてくる。
ホーム画面に登録すると、iconsで指定した画像が表示。
アイコンをクリックするとPWAが起動する。スプラッシュ画面のバックグラウンドカラー、および表示アイコンは、manifest.jsonで指定された内容が反映される。
Android 機種でインストールした PWAは、アプリ管理画面上でアンイストールができる。ホーム画面のアイコンを削除しただけでは、アンインストールされない。
スマホをオフラインにした状態。ブラウザでアクセスしている画面は表示ができないが、PWAはオフラインでも起動が可能。
今回のサンプルでは、Service Worker に登録した Cache Storage のkeyに「CACHE_NAME」を利用している。
Cache Storage のkey に変更があった場合 (=Service Worker ファイルに変更があった場合)
以下は、Chrome の拡張機能で見たService Workerのキャッシュ入れ替えの様子。
Consoleに、新しいデータがキャッシュされるとともに、Cache Storage の入れ替えを待っていることがわかる。
画像中、CacheStorage に同じアプリからキャッシュされた2つのデータが存在するが、ブラウザ・アプリを閉じてからもう一度開き直すと、古いキャッシュが削除され、新しいキャッシュが登録される。
オフライン状態でコンテンツを表示するためには、コンテンツデータをキャッシュする必要がある。
オフライン状態でも、コンテンツが見れるようにアプリを修正する。
以下は、Google のチュートリアル記事
https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa?hl=ja
上記の記事中では
IndexedDBは、NoSQLライクなブラウザ用のローカルストレージ。
IndexedDBを利用して、オフラインで直前のキャッシュデータを表示するVer.3 を開発する。仕様は以下とする。
実際に動いているサンプルはこちら。
https://newqiitapost.firebaseapp.com/v3/
Ver.2からの変更点は、main.js。取得してきたQiitaの記事を、localforage経由でIndexedDBに保存するようにした。
main.js
プッシュ通知実装について書くつもりだったが、想像以上にボリュームがあったため、稿を分けて別記事として公開予定。
PWAにおける各ブラウザの容量上限は以下
(2019/2時点 Googleの記事より引用)
IndexedDBは以下のようなテスト結果があった
http://iwatendo.hateblo.jp/entry/2018/02/15/215811
PWA、そしてService Worker を利用したキャッシュは便利な反面、のべつ幕なしに全ファイルをキャッシュしようとするとバグの温床になりそう。
特に、多量のファイルおよびデータをすべてキャッシュさせようとすると、必要以上にブラウザ、そしてデバイスのディスク容量を圧迫する。
どこまでをキャッシュさせ、どこまでは動的にフェッチするかは、PWAを開発する上でとても重要だろう。
Chrome の検証ツールに「Application」というタブがあり、このタブを使うことでPWAの各種シミュレーションやデバッグが行える。詳しくは下記の記事「Service Worker のデバッグ」を参照。
https://developers.google.com/web/fundamentals/codelabs/debugging-service-workers/?hl=ja
Chromeの拡張機能となるが、Lighthouseを使うと、公開前のウェブアプリが一通りチェックできる。
https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa?hl=ja
Google の記事
https://developers.google.com/web/tools/lighthouse/
Qiita のLighthouse タグ
https://qiita.com/tags/lighthouse
Google のチュートリアル。網羅的で、実際のサンプルコードもあり、非常に勉強になる。自分のようなPWA初学者は必読
https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/debugging-service-workers/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/offline/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/push-notifications/?hl=ja
Google のドキュメントはどうしてもGoogle が提唱する環境中心の記述になるため、MDNも合わせて読むとより理解が深まる。
https://developer.mozilla.org/ja/docs/Web/Apps/Progressive
Mozzila によるレシピブック集
https://serviceworke.rs/
IndexedDBのリファレンス
https://www.w3.org/TR/IndexedDB/
https://developer.mozilla.org/ja/docs/Web/API/IndexedDB_API
https://developer.mozilla.org/ja/docs/Web/API/IndexedDB_API/Using_IndexedDB
localforgeのリファレンス
https://localforage.github.io/localForage/
今回のサンプルではlocalForageを利用したが、IndexedDBの操作に使えるライブラリは他にもある。
以下はMDNからの引用。
事例サイト
https://pwa.rocks/
「これもPWAなの?」と驚いたPWAを2つ紹介
https://pokedex.org/
カントー地方のポケモンデータベース。画像はCSSスプライトで、ポケモンのデータはIndexedDBで管理されている。
https://shinycolors.enza.fun
https://shinycolors.idolmaster.jp/
ブラウザゲーですが、Android機ではPWA対応アプリとして、実機にインストールして使える。
キャラクターのアニメーションなど、ウェブ技術でここまで作り込めるのか、と思いました(小並感)。
Qiita のAPIを何度も叩いてわかったことは、想像以上にスパム投稿が多いのだな、ということ。人気投稿サイトは狙われやすいのですね。
運営者の皆様、お疲れ様です。
この記事について
PWAについて勉強中の人間(=自分)のためのメモです。PWAについての理解がふわっとしていたので、おさらいし直した内容を記しました。
2019年2月時点のメモとなりますが、誤記などありましたらどうぞご指摘ください。
Progressive Web Apps とは
Google が提唱・推進しているアプリhttps://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/?hl=ja
概念はGoogle の説明を参照するとして、仕様面で見ると
- Web技術 (html、css、JavaScript、および各種 Web API) を利用したアプリ
- ウェブサイトで公開可能、Appストアを経由せずに配布できる
- スマートフォンにインストール可能
- Service Worker を利用し、アプリプログラムをキャッシュすることで、ネットにつながっていなくても動作可能
- 通常のウェブアプリはネットへ接続できる状態を前提としている
- プッシュ通知を使うことで、利用ユーザーに対する通知が可能
ウェブ技術を使っているという点で、Apache Cordova を利用したハイブリッドアプリに近い。
ただし、PWAはウェブ経由で配布可能であり、パッケージ化するにあたって Apache Cordova などのライブラリは必ずしも必要としない。
ブラウザによって各種APIの実装状況は異なるため、すべてのブラウザ環境、スマホ環境で使えるわけではない。
(2019年2月の段階)
App Shellについて
https://developers.google.com/web/fundamentals/architecture/app-shell?hl=jaPWAのコアにあたる。
特別な技術のような響きがあるが、「アプリが動く枠組み部分」「アプリ用テンプレート」と言った概念を言語化したもの。たとえば、下記のようなシンプルなhtmlでも「App Shell」になりうる。
<div id="main">のDOMに、各種情報をフェッチすれば、PWA の App Shell として成立する。
<!DOCTYPE HTML> <html> <head> <title>App Shell</title> </head> <body> <div id="main"></div> </body> </html>
(明確な定義がないため「どこまでがシンプルなのか」は、実装者の判断になりうる)
Service Worker (サービスワーカー) について
https://developers.google.com/web/fundamentals/primers/service-workers/?hl=jaウェブページからの入力とは独立して、ブラウザのバックグラウンドで動作する。
プッシュ通知やバックグラウンド同期などを行う。
将来的にさらなる機能拡張が予定されている。
オフラインの状態でも何らかの形でアプリが動作するようサポートする機能が実装されている。
Promiseを多用するため、Promiseの概念・挙動を理解しておく必要がある。
Service Workerを利用するためには、明示的に有効化する必要がある。
下記はGoogle のチュートリアルに記載されている、Service Workerを有効化するサンプルコード。
if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js').then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }); }
Service Worker の振る舞いは、Service Worker 登録用のファイルにJavaScript のコードとして記述する必要がある。
Push通知について
PWAユーザーに対して通知を送れる機能。ユーザーに通知を送るAPIとしては
の2つがある。PWAの世界で一般的に「プッシュ通知」について説明する場合、後者のPush APIを利用したものを指す。
Push APIを利用すると、アプリを利用中のユーザーに対してプッシュ通知を送ることができるが、通知用のサーバーが必要になる。また、秘密鍵と公開鍵を作成して、アプリ側に公開鍵をセットする必要がある。
プッシュ通知はサーバーが必要なことから、Firebase を利用した実装を見ることが多い。
(必ずしもFirebaseである必要はないが、Firebaseを使う実装が手っ取り早い)
Google のチュートリアルでは、Nodeを使ったテスト用のサーバーを紹介している。
PWAの対応ブラウザ
Service Worker、Fetch API、Push API が動作するブラウザ が PWA対応ブラウザ、と言っても良さそう。各ブラウザの Service Worker の対応状況は以下が参考になる。2016年頃と比べると、ずいぶん対応が進んでいる。
https://caniuse.com/#search=Service%20Workers
Fetch APIの対応状況は以下
https://caniuse.com/#search=Fetch%20api
Push API
https://caniuse.com/#search=push%20api
実際のアプリ
簡単なPWA対応アプリを作り、挙動を見てみる。アプリの仕様は以下とする。
- Qiita の最新記事を確認できるアプリ
- 立ち上げ時に、その時点の最新記事タイトルをリンク付きで表示する。
- ボタンを押すと、QiitaのAPIを叩き、最新記事を再取得、再描画する。
PWA対応していないウェブアプリ
まずは、PWA対応をしていない、普通のウェブアプリの状態で作ってみた。サンプルは以下。
https://newqiitapost.firebaseapp.com/v1/
コードは以下の通り。
index.html
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="utf-8" /> <title>Qiita の最新投稿取得アプリ V1</title> <link rel="stylesheet" href="./bootstrap.min.css"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="./main.js"></script> </head> <body> <div class="col-sm-3"></div> <div class="col-sm-6"> <h1 class="text-center">Qiita の最新投稿取得アプリ V1</h1> <h2 id="newitem" class="text-center"></h2> <button id="button" onclick="getPost()" class="btn center-block">クリックして最新投稿を確認</button> </div> <div class="col-sm-3"></div> </body> </html>
"use strict"; getPost(); function getPost() { fetch('https://qiita.com/api/v2/items') .then(response => { return response.json(); }).then(res => { const title = res[0].title; const url = res[0].url; const data = `<a href="${url}">${title}</a>`; document.getElementById("newitem").innerHTML = data; }).catch(function (error) { console.log(error); }); }
スマートフォンにアプリとしてインストール可能にする
スマートフォンにインストールしてアプリのように利用するためには- manifest.jsonの設定
- Service Worker 登録
https://developers.google.com/web/fundamentals/web-app-manifest/?hl=ja
https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ja
manifest.jsonの設定
manifst.jsonでは- short name
- ユーザーのホーム画面でテキストとして使用
- name
- ウェブアプリのインストール バナーに使用
- icons
- アプリのアイコン画像。スマホのホーム画面登録時、および起動時のスプラッシュ画面などに使われる。
- start_url
- 起動時のURL。省略可能だが、指定したほうが良い。省略した場合、登録時に表示されている画面のURLが起動画面となる
- background_color
- アプリ起動時のスプラッシュ画面の背景色
- display
- アプリの表示タイプ。「standalone」を指定すると、ブラウザのUIが非表示となり、アプリっぽい画面になる。「browser」を指定すると、ブラウザのUIが利用される。
- orientation
- 指定すると、アプリ使用時の画面の向きを矯正する。「landscape」を指定するとスマホを横向けにした操作画面となる。「portrait」を指定すると縦向けの操作となる。
これを踏まえて、manifest.jsonを作成。以下は例。
{ "short_name": "Qiita の最新投稿取得アプリ V2", "name": "Qiita の最新投稿取得アプリ V2", "icons": [ { "src": "icon-192-192.png", "type": "image/png", "sizes": "192x192" }, { "src": "icon-512-512.png", "type": "image/png", "sizes": "512x512" } ], "start_url": "index.html", "display": "standalone", "orientation": "portrait", "background_color": "#00C721F" }
Service Worker を利用したデータキャッシュ
次に、Service Worker 登録用のJSを作成する。Service Worker 登録用のファイルでは大まかに言って
- キャシュするファイルの定義
- スコープの定義
- キャッシュのインストール、フェッチ、アクティベートの設定
先に作ったVer1のウェブアプリでは
- index.html
- main.js
- bootstrap.min.css
index.html。head内で 「manifest.json」を読み込んでいる。
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="utf-8" /> <title>Qiita の最新投稿</title> <link rel="stylesheet" href="./bootstrap.min.css"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="./main.js"></script> <link rel="manifest" href="./manifest.json"> </head> <body> <div class="col-sm-3"></div> <div class="col-sm-6"> <h1 class="text-center">Qiita の最新投稿</h1> <h2 id="newitem" class="text-center"></h2> <button id="button" onclick="getPost()" class="btn center-block">クリックして投稿情報を確認</button> </div> <div class="col-sm-3"></div> </body> </html>
"use strict"; registSW(); getPost(); function registSW() { // Service Worker 対応ブラウザの場合、スコープに基づいてService Worker を登録する if ('serviceWorker' in navigator) { window.addEventListener('load', function () { navigator.serviceWorker.register('./sw.js', { scope: './' }).then(function (registration) { console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function (err) { console.log('ServiceWorker registration failed: ', err); }); }); } } function getPost() { fetch('https://qiita.com/api/v2/items') .then(response => { return response.json(); }).then(res => { const title = res[0].title; const url = res[0].url; const data = `<a href="${url}">${title}</a>`; document.getElementById("newitem").innerHTML = data; }).catch(function (error) { console.log(error); }); }
// Service Worker のバージョンとキャッシュする App Shell を定義する const NAME = 'qiita-post-app-v2-'; const VERSION = '002'; const CACHE_NAME = NAME + VERSION; const urlsToCache = [ './index.html', './main.js', './bootstrap.min.css', ]; // Service Worker へファイルをインストール self.addEventListener('install', function (event) { event.waitUntil( caches.open(CACHE_NAME) .then(function (cache) { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); }); // リクエストされたファイルが Service Worker にキャッシュされている場合 // キャッシュからレスポンスを返す self.addEventListener('fetch', function (event) { if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') return; event.respondWith( caches.match(event.request) .then(function (response) { if (response) { return response; } return fetch(event.request); }) ); }); // Cache Storage にキャッシュされているサービスワーカーのkeyに変更があった場合 // 新バージョンをインストール後、旧バージョンのキャッシュを削除する // (このファイルでは CACHE_NAME をkeyの値とみなし、変更を検知している) self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keys => Promise.all( keys.map(key => { if (!CACHE_NAME.includes(key)) { return caches.delete(key); } }) )).then(() => { console.log(CACHE_NAME + "activated"); }) ); });
https://newqiitapost.firebaseapp.com/v2/
このアプリをAndroidのスマホブラウザ(Chrome)で見ると、ホーム画面に登録するか (=インストールするか) を聞いてくる。
ホーム画面に登録すると、iconsで指定した画像が表示。
アイコンをクリックするとPWAが起動する。スプラッシュ画面のバックグラウンドカラー、および表示アイコンは、manifest.jsonで指定された内容が反映される。
Android 機種でインストールした PWAは、アプリ管理画面上でアンイストールができる。ホーム画面のアイコンを削除しただけでは、アンインストールされない。
スマホをオフラインにした状態。ブラウザでアクセスしている画面は表示ができないが、PWAはオフラインでも起動が可能。
Service Worker のキャッシュ更新
今回のサンプルでは、Service Worker に登録した Cache Storage のkeyに「CACHE_NAME」を利用している。Cache Storage のkey に変更があった場合 (=Service Worker ファイルに変更があった場合)
- 新しいService Worker のファイルをキャッシュ
- 古いキャッシュファイルの削除
以下は、Chrome の拡張機能で見たService Workerのキャッシュ入れ替えの様子。
Consoleに、新しいデータがキャッシュされるとともに、Cache Storage の入れ替えを待っていることがわかる。
画像中、CacheStorage に同じアプリからキャッシュされた2つのデータが存在するが、ブラウザ・アプリを閉じてからもう一度開き直すと、古いキャッシュが削除され、新しいキャッシュが登録される。
オフライン時でもコンテンツデータが見れるようにする
オフライン状態でコンテンツを表示するためには、コンテンツデータをキャッシュする必要がある。オフライン状態でも、コンテンツが見れるようにアプリを修正する。
以下は、Google のチュートリアル記事
https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa?hl=ja
上記の記事中では
をそれぞれ推奨するとの記述がある。
- URL 指定可能なリソース (=App Shell) は、Cache API(Service Worker の一部)を使用
- その他のすべてのデータには、(Promise ラッパーで)IndexedDB を使用
IndexedDBは、NoSQLライクなブラウザ用のローカルストレージ。
IndexedDBを利用したコンテンツキャッシュを行いオフライン対応する
IndexedDBを利用して、オフラインで直前のキャッシュデータを表示するVer.3 を開発する。仕様は以下とする。- Qiita の最新記事を確認できるアプリ
- 立ち上げ時に、その時点の最新記事タイトルをリンク付きで表示する。
- ボタンを押すと、QiitaのAPIを叩き、最新記事を再取得、再描画する。
- PWAとしてスマホにインストール可能
- スマホインストール後、オフラインの状態のときは、直近に取得した記事情報を表示する。オンラインに変わったら、キャッシュした記事情報を削除して、最新の記事に入れ替える。
- 以後、Qiitaから最新記事を取得するたびに、IndexedDBのデータを入れ替える。
実際に動いているサンプルはこちら。
https://newqiitapost.firebaseapp.com/v3/
Ver.2からの変更点は、main.js。取得してきたQiitaの記事を、localforage経由でIndexedDBに保存するようにした。
- 関数 getPostで、Qiita のAPIからレスポンスを取得
- 通信が成功した場合、最新の記事を表示して、IndexedDBにでーたを保存する。
- key は「qiita」、valueはQiitaの記事をJSONのまま登録
- 通信が失敗した場合、関数 displayLocalを呼び出し
- IndexedDBにデータが存在する場合、そのデータを呼び出して表示
- IndexedDBにデータがない場合、再通信を促すメッセージを表示する
main.js
"use strict"; registSW(); getPost(); function registSW() { if ('serviceWorker' in navigator) { window.addEventListener('load', function () { navigator.serviceWorker.register('./sw.js', { scope: './' }).then(function (registration) { console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function (err) { console.log('ServiceWorker registration failed: ', err); }); }); } } function getPost() { fetch('https://qiita.com/api/v2/items') .then(response => { return response.json(); }).then(res => { const title = res[0].title; const url = res[0].url; const data = `<a href="${url}">${title}</a>`; document.getElementById("newitem").innerHTML = data; localforage.setItem('qiita', res[0]); }).catch(function (error) { displayLocal(); }); } function displayLocal() { localforage.getItem('qiita').then(cache => { const title = cache.title; const url = cache.url; const data = `<a href="${url}">${title}</a>`; document.getElementById("newitem").innerHTML = data; }).catch(function (err) { console.log(err); const data = '<p>通信状況の良い場所でお試しください。</p>'; document.getElementById("newitem").innerHTML = data; }); }
プッシュ通知
プッシュ通知実装について書くつもりだったが、想像以上にボリュームがあったため、稿を分けて別記事として公開予定。
備忘録
PWAが使えるディスク容量
PWAにおける各ブラウザの容量上限は以下(2019/2時点 Googleの記事より引用)
- Chrome
- 空き領域の 6% 未満
- Firefox
- 空き領域の 10% 未満
- Safari
- 50MB
- IE10
- 250MB
IndexedDBは以下のようなテスト結果があった
http://iwatendo.hateblo.jp/entry/2018/02/15/215811
App Shell の規模感とキャッシュのメリット・デメリット
PWA、そしてService Worker を利用したキャッシュは便利な反面、のべつ幕なしに全ファイルをキャッシュしようとするとバグの温床になりそう。特に、多量のファイルおよびデータをすべてキャッシュさせようとすると、必要以上にブラウザ、そしてデバイスのディスク容量を圧迫する。
どこまでをキャッシュさせ、どこまでは動的にフェッチするかは、PWAを開発する上でとても重要だろう。
PWAのデバッグ
Chrome の検証ツールに「Application」というタブがあり、このタブを使うことでPWAの各種シミュレーションやデバッグが行える。詳しくは下記の記事「Service Worker のデバッグ」を参照。https://developers.google.com/web/fundamentals/codelabs/debugging-service-workers/?hl=ja
PWAの公開前チェック
Chromeの拡張機能となるが、Lighthouseを使うと、公開前のウェブアプリが一通りチェックできる。https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa?hl=ja
Google の記事
https://developers.google.com/web/tools/lighthouse/
Qiita のLighthouse タグ
https://qiita.com/tags/lighthouse
各種学習リソース
Google のチュートリアル。網羅的で、実際のサンプルコードもあり、非常に勉強になる。自分のようなPWA初学者は必読https://developers.google.com/web/fundamentals/primers/service-workers/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/debugging-service-workers/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/offline/?hl=ja
https://developers.google.com/web/fundamentals/codelabs/push-notifications/?hl=ja
Google のドキュメントはどうしてもGoogle が提唱する環境中心の記述になるため、MDNも合わせて読むとより理解が深まる。
https://developer.mozilla.org/ja/docs/Web/Apps/Progressive
Mozzila によるレシピブック集
https://serviceworke.rs/
IndexedDBのリファレンス
https://www.w3.org/TR/IndexedDB/
https://developer.mozilla.org/ja/docs/Web/API/IndexedDB_API
https://developer.mozilla.org/ja/docs/Web/API/IndexedDB_API/Using_IndexedDB
localforgeのリファレンス
https://localforage.github.io/localForage/
今回のサンプルではlocalForageを利用したが、IndexedDBの操作に使えるライブラリは他にもある。
以下はMDNからの引用。
-
Dexie.js
- 優良でシンプルな構文により高速なコード開発を可能にする、IndexedDB のラッパーとのこと
-
ZangoDB
- MongoDB ライクなIndexedDB用インターフェイス
-
MiniMongo
- MeteorJSで使われているらしい
- PouchDB
PWAのアプリ例
事例サイトhttps://pwa.rocks/
「これもPWAなの?」と驚いたPWAを2つ紹介
Pokedex.org
https://pokedex.org/カントー地方のポケモンデータベース。画像はCSSスプライトで、ポケモンのデータはIndexedDBで管理されている。
アイドルマスターシャイニーカラーズ
https://shinycolors.enza.funhttps://shinycolors.idolmaster.jp/
ブラウザゲーですが、Android機ではPWA対応アプリとして、実機にインストールして使える。
キャラクターのアニメーションなど、ウェブ技術でここまで作り込めるのか、と思いました(小並感)。
その他
Qiita のAPIを何度も叩いてわかったことは、想像以上にスパム投稿が多いのだな、ということ。人気投稿サイトは狙われやすいのですね。運営者の皆様、お疲れ様です。
コメント
コメントを投稿