PWAについて　簡単な実装方法も紹介！

# はじめに
この記事は[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)です。
このカレンダーでは、なんとなくわかった気になっている、Webの知識をおさらいするカレンダーです。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

今回はPWAについて説明します！

## PWAとは

Progressive Web Appsの略で、Googleが提唱した概念のことです。
Webアプリとネイティブアプリの利点を兼ね備えたWebアプリのことです。

Webアプリはインストールせずともすぐ使えて、アクセスしやすく、他の人にも共有がしやすいという特徴があります。
一方、ネイティブアプリはオフラインでも動作できたり、ホーム画面のアイコンからすぐにアクセスできたり、通知を飛ばせたりします。

こういった双方の良い特徴を融合させて作られたWebアプリのことをPWAといいます。

### PWAを満たすための原則

では、具体的にはPWAはどんな特徴を持つのかについて、説明します。

[MDN](https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps/Introduction)より引用

> * 発見可能 (検索エンジンで見つけることができる)
> * インストール可能 (アプリを端末のホーム画面に追加できる)
> * リンク可能 (URLを送るだけで共有できる)
> * ネットワーク非依存 (オフライン　あるいは貧弱なネットワーク環境でも使用できる)
> * 進化的 (古いブラウザでも基本的な機能は使用でき、最新のブラウザではすべての機能が使用可能)
> * 再エンゲージ可能 (通知を送ることができる)
> * レスポンシブデザイン (どの端末であっても使用できる )
> * 安全性 (第三者からの攻撃に対して安全であり、機密情報を保護できる)

表示速度が速く、オフラインで使用できるのでユーザーの直帰率を減らせたり、
通知を送ることでユーザーの再訪率を増やすことができます。

また、アプリを開発するよりもコストやリソースが大幅に抑えられるのもメリットです。

### PWAを導入する方法
それでは、 PWAをどうやって組み込んでいくのかについて説明します。
下記三つの対応が必要です。

* Webサイトをhttps化する
    * SSL証明書を発行して、サイトに反映させましょう。
    * 具体的な方法は割愛します。
* マニフェストファイルの作成
    * アプリの画像や名前など端末のホーム画面で使用するためのもの
* ServiceWorkerを設定する
    * ServiceWorkerについては、[別の記事](https://qiita.com/yutaroud/items/a39124b940d73a663497)で説明しています。
        * オフライン操作やプッシュ通知などPWAの基盤となる機能の実装に必要なもの

#### 実際に作ってみる
github pagesで試してみました。
https://yutaroud.github.io/pwa_test/

ページを見ると、アプリをインストールしますか？というお知らせが来るので有効化します。
![スクリーンショット 2022-12-23 22.24.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224825/8835b81c-98a4-604e-6b06-f0b1141c6d9e.png)

有効化すると下記のように、実際のアプリのように登録され、すぐに開けるようになります。
![スクリーンショット 2022-12-23 22.25.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224825/ca3d4ff4-52ba-575d-22e0-c6746054dda3.png)
![スクリーンショット 2022-12-23 22.24.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224825/eaa9b43d-cd8f-0301-5ae6-ab0631325605.png)

[こちら](https://github.com/yutaroud/pwa_test)で公開しているので、ご自由にお使いください。

#### コードの解説

manifest.jsonとservice worker をindex.htmlで下記のように読み込みます。
ifで囲む必要があるのは、serviceWorkerが使えないブラウザへの対策です。

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="manifest" href="./manifest.json">
  <link rel="stylesheet" href="./css/styles.css">
  <script>      
      if (navigator.serviceWorker) {
        navigator.serviceWorker.register ('/pwa_test/service-worker.js')
      }
  </script>
  <title>PWA test</title>
</head>
<body>
  <h1>PWA Test</h1>
</body>
</html>
```

manifest.jsonには、アプリとしてインストールされるときの名前やアイコンなどを指定します。
`display: standalone` というのは、アプリとして開いたときに全画面表示の状態で開くようにするという設定です。
詳しくは[MDN](https://developer.mozilla.org/ja/docs/Web/Manifest/display)を参照するのが良いと思います。

```manifest.json
{
  "name": "PWA Test",
  "short_name": "PWA",
  "background_color": "#000000",
  "icons": [{
      "src": "/pwa_test/img/icon.png",
      "sizes": "256x256",
      "type": "image/png"
    }],
  "start_url": "/pwa_test/",
  "scope": "/pwa_test/",
  "display": "standalone"
}
```

installでは、Service Workerを新規インストールしたときに行われる処理を書きます。
例えば、指定したリソースをキャッシュに保存するなどです。

activateは、Service Workerのインストールが完了して、有効に機能したときに発火します。
古いキャッシュを削除したりします。


fetchは、リソースのリクエストが発生したときに発火します。
使い方の例だと、リソースのリクエストが発生したときにキャッシュがあればキャッシュを使って、なければサーバーにリクエストを投げてキャッシュに保存させる
などです。

```service-worker.js
self.addEventListener('fetch', function (e) {
  console.log('service worker fetch')
})

self.addEventListener('install', function (e) {
  console.log('service worker install')
})

self.addEventListener('activate', function (e) {
  console.log('service worker activate')
})
```


通知やキャッシュなどを入れる場合は別途設定が必要です。
通知は[Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging)などの外部サービスを使うのがおすすめです。

# まとめ
簡単にですが、PWAについてまとめました！
PWAをうまく使いこなすことができれば、ユーザー体験の向上が図れるので、皆さんぜひ取り入れてみてください！

[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)でした。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

## 参考文献
[pwa template](https://github.com/codepo8/github-page-pwa)