はじめに
前回、indexedDB を使ってTodoアプリを作ってみました。
Todoなのでしょっちゅう確認したり更新したりするので、アクセス頻度は自ずと高くなりますよね
常にPCを持ち歩くわけにもいかず、ブックマークしてもスマホのブラウザではやっぱり使いにくい...
っということで、今回はこのTodoアプリを PWA 化してスマホでネイティブアプリと同じ感じで使えるようにしてみたいと思います。
前回の記事はこちらです。
PWAとは
PWA について簡単に紹介しておきましょう
PWA って何?
私は、ちょうど1年くらい前に PWA を知りました。スマホ向けのアプリを試作する機会があり、
App StoreやGoogle Playを通さずに試作版を試してみたいというニーズからWebアプリで
ネイティブアプリの様な使い方はできないものかと色々調べ、PWA という技術に出会いました。
ちょっと大仰に書きましたが、PWA とは
Progressive Web Application の略でネイティブアプリの様に動作させられるWebアプリのことです。
その特徴を簡単に言うなら
- 素早いレスポンス
- オフライン対応
- ホーム画面へのアイコン追加
といったところでしょうか
っで、どんな技術?
PWA は ServiceWorker という技術で成り立っています。この ServiceWorker とは、ブラウザがそのUIとは別にバックグランドで動作させるスクリプトのことです。
っと言われてもピンとこないと思いますが、
ブラウザとWebサーバーの中間に居て、ブラウザからのネットワークリクエストやWebサーバーからのレスポンスをキャッシュしたり、Webからのプッシュ通知を受け付けたり、といろんなことをやってくれる
ブラウザのバックグランドタスクみたいにイメージすると理解しやすいかもしれません。
詳しくは
Service Workers: an Introduction | Web Fundamentals | Google Developers
に説明があります。
この ServiceWorker を使うには
- ブラウザがサポートしていること
- HTTPS通信であること
という条件があります。
大半のブラウザは既にサポートされているようですが、 詳しくは以下のサイトで確認できます。
Is service worker ready?
HTTPS通信はWebサイトに依存しますが、今回の記事で紹介するサンプルは github.io を使っています。
Vue のアプリを github.io で公開する方法は後述します。
出来上がりはこんな感じです
iphoneのホーム画面にアイコンを追加、アプリを起動させるとこんな感じになります。

アプリをPWA対応にするには
では、前回のTodoアプリを PWA に対応させてみましょう。
ちょっとその前に...
さきほど、PWA は ServiceWorker という技術で成り立っていると説明しました。
上述した通り ServiceWorker は、ブラウザとWebサーバーの中間に居てリクエストとレスポンスをキャッシュしてオフライン時の動作を可能にしますが、実はこのキャッシュポリシーが ServiceWorker の実装上の一つの課題になっています。
キャッシュすべき情報はアプリによって様々なのと何をキャッシュし、いつ消去するかといった設計上の画一的ルールはないため、本来はアプリの設計者がユースケースに応じて決めなければなりません。
さらに ServiceWorker は定型的なロジックが多く、ライフサイクルの状態遷移が複雑なこともあり実装には何かと手間がかかります。
実はそういった煩わしさを軽減するライブラリがあり、Googleが提供する Workbox もそういったライブラリの一つです。
Vue では vue cli が Workbox を使って ServiceWorker を自動生成してくれるのでとても簡単に PWA に対応させることができます。
最初からPWAでやる
vue create でプロジェクトを作成するときに PWA を指定します。
こんな感じです。
Manual Selectを選択し

Progressive Web App(PWA) Support をチェックします。

既存のアプリをPWAにする
プロジェクトフォルダ内で vue add @vue/pwa とすることで既存のアプリを PWA 対応にできます。
コマンドを実行するとこんな感じでPWA 関連のファイルがインストールされます。
PS C:\Shikataramuno\vue-ts-indexed-db-as-pwa> vue add @vue/pwa
📦 Installing @vue/cli-plugin-pwa...
> core-js@2.6.9 postinstall C:\Shikataramuno\vue-ts-indexed-db-as-pwa\node_modules\core-js
> node scripts/postinstall || echo "ignore"
vue-ts-indexed-db-as-pwa@0.1.0 C:\Shikataramuno\vue-ts-indexed-db-as-pwa
`-- @vue/cli-plugin-pwa@3.8.0
`-- workbox-webpack-plugin@3.6.3
+-- babel-runtime@6.26.0
| +-- core-js@2.6.9
| `-- regenerator-runtime@0.11.1
+-- json-stable-stringify@1.0.1
`-- workbox-build@3.6.3
+-- common-tags@1.8.0
+-- fs-extra@4.0.3
+-- joi@11.4.0
| +-- hoek@4.2.1
| +-- isemail@3.2.0
| `-- topo@2.0.2
+-- lodash.template@4.4.0
| +-- lodash._reinterpolate@3.0.0
| `-- lodash.templatesettings@4.1.0
+-- pretty-bytes@4.0.2
+-- stringify-object@3.3.0
| +-- get-own-enumerable-property-symbols@3.0.0
| `-- is-regexp@1.0.0
+-- strip-comments@1.0.2
| +-- babel-extract-comments@1.0.0
| | `-- babylon@6.18.0
| `-- babel-plugin-transform-object-rest-spread@6.26.0
| `-- babel-plugin-syntax-object-rest-spread@6.13.0
+-- workbox-background-sync@3.6.3
+-- workbox-broadcast-cache-update@3.6.3
+-- workbox-cache-expiration@3.6.3
+-- workbox-cacheable-response@3.6.3
+-- workbox-core@3.6.3
+-- workbox-google-analytics@3.6.3
+-- workbox-navigation-preload@3.6.3
+-- workbox-precaching@3.6.3
+-- workbox-range-requests@3.6.3
+-- workbox-routing@3.6.3
+-- workbox-strategies@3.6.3
+-- workbox-streams@3.6.3
`-- workbox-sw@3.6.3
✔ Successfully installed plugin: @vue/cli-plugin-pwa
🚀 Invoking generator for @vue/cli-plugin-pwa...
📦 Installing additional dependencies...
vue-ts-indexed-db-as-pwa@0.1.0 C:\Shikataramuno\vue-ts-indexed-db-as-pwa
`-- register-service-worker@1.6.2
✔ Successfully invoked generator for plugin: @vue/cli-plugin-pwa
The following files have been updated / added:
public/img/icons/android-chrome-192x192.png
public/img/icons/android-chrome-512x512.png
public/img/icons/apple-touch-icon-120x120.png
public/img/icons/apple-touch-icon-152x152.png
public/img/icons/apple-touch-icon-180x180.png
public/img/icons/apple-touch-icon-60x60.png
public/img/icons/apple-touch-icon-76x76.png
public/img/icons/apple-touch-icon.png
public/img/icons/favicon-16x16.png
public/img/icons/favicon-32x32.png
public/img/icons/msapplication-icon-144x144.png
public/img/icons/mstile-150x150.png
public/img/icons/safari-pinned-tab.svg
public/manifest.json
public/robots.txt
src/registerServiceWorker.ts
package.json
src/main.ts
You should review these changes with git diff and commit them.
とっても簡単ですね!
アプリを公開するには
上述したとおり、PWA は https でなければなりません。
既に、そのようなサイトを公開されている場合は別ですが、これから https サイトを新たに公開するとなると何かと手間がかかるのではないかと思います。
ここでは、手軽に https で試す方法として github.io で公開するやり方を紹介します。
まず、
GitHub上に公開ページ用にリポジトリを作ります。docsフォルダ以下に公開用の一連のファイルをコピーし、GitHubにpushします。GitHubのリポジトリページ上で、[Setting]→[GitHub Pages]→[Source]で、[master branch/docs folder]を指定します。そうすると、https://ユーザー名.github.io/リポジトリ名/というURLで公開できます。
基本、これだけです!
では、前回記事の
https://github.com/Shikataramuno/vue-ts-Indexed-DB.git
をビルドしてアップしてみましょう。
っとここでもその前に若干の修正が必要です。
Vue では production モードのビルドでは、公開用ファイルの出力先が dist フォルダで、URLのルートからのパスで公開用ファイルが生成されます。
github.io で公開する場合、プロジェクト名のサブフォルダがアプリのルートになるので、そのままでは正しく表示されません。
そこで、プロジェクトフォルダの直下に vue.config.js というコンフィグ用のファイルを作成し、以下の内容を記述しておきます。
module.exports = { publicPath: process.env.NODE_ENV === 'production' ? '/vue-ts-indexed-db-as-pwa/' : '/', outputDir: 'docs', };
これで npm run build して docs フォルダ以下を Github に push すれば、正しく表示されます。
このサイトを参考にさせていただきました。
Vue CLI 3 で PWA のアプリつくって GitHubPages で公開 - Qiita
出来上がり!
実際にスマートホンで以下QRコードを読み取りアクセスしてみてください。

ちなみにアクセス先は以下です。
https://shikataramuno.github.io/vue-ts-indexed-db-as-pwa/
Todoアプリが表示されると思います。
ホーム画面に追加するとアイコンが表示されます。これをクリックするとネイティブアプリの様にTodoアプリが起動し、
通常と同じ操作ができるようになると思います。試してみてください。
こんな感じです。

さらに!
機内モードにしてアプリを起動してみてください。
通常通りの操作が可能と思います。オフラインでもTodoの確認、追加、変更、削除が可能です。
これって地味にすごい!って感じですね indexedDb + PWA の威力でしょう!
(やっぱりTodoアプリはこうじゃないとね!)
謝辞
今回は indexedDB を使ったTodoアプリを PWA 対応にしてみました。
URLにアクセス、ホーム画面に追加したらネイティブアプリと遜色ない使い心地でよかったです。
最近何かと PWA が話題ですが、ストアを経由せずともアプリをインストールできるので手軽かつ
once write run anywhereが実現できるので色々と重宝しそうです。
最後まで読んでいただき、ありがとうございました。
皆様の何かのお役に立てたなら幸いです。