PWAとは何か？大体わかるようになる

今回PWAを勉強した理由は「Google サンタを追いかけよう」の存在を知って周りが盛り上がり、PWAってなんや？ってところからでした。~~いつまで知らなかったんや~~
僕自身もフロント全般的に知識が浅いので初心者の方にもなんとなく理解できるんじゃないかなと思っています。

# PWAってなんすか？
よく説明されるのは**PWAとは「Progressive Web Apps」の略称でモバイル向けのwebサイトをアプリのように使える仕組み**と言われています。
PWAはアプリとWebサイトの側面を持ち合わせています。　普段アプリを使っていればなんとなくイメージはつくのではないでしょうか？

一点注意したいのは、**1つの技術をPWAと言うのではなく、様々なGoogleが定めている要素を備えたウェブアプリのことを言います**
定める要素は主に4つに分類されています。:relaxed:

| 分類項目 | 意味 |
|:-----------------|------------------|
| Reliable | ネットワークの状態に関係なく読み込むことができる。 |
| Integrated | 体験をよりデバイス・OSに合わせた形にする。 |
| Fast | 操作に素早く反応すること。 |
| Engaging | のめり込むようなUXがあること。 |

んー・・・概念的すぎてよくわからないっすよね。
後に機能や技術の話をしますが、push通知やオフライン対応で解釈してしまうとそれはPWAの一部にすぎません。
学習を通して自分の解釈としては、PWAとは**よりよいウェブ体験をアプリのように作ることができること**ではないかなと思っています。
なぜかと言うと下の表のようにwebとアプリを比較してwebでできなかったことがPWAではできるからです。

**PWAとwebサイト・ネイティブアプリの比較表**
![PWA比較表.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/2ed2ed97-86fd-a33b-eb29-896a1b6f43ac.png)
> 引用元：https://slidesplayer.net/slide/14321401/

## PWAでできること
比較表でネタバレしている部分もあるのですが、代表例を紹介させてください。

### ユーザーの端末にインストールできる
webサイトからアプリへ誘致するためにはインストールという手間が入るように、ユーザーと企業にとっての利用障壁となる存在は今も課題です。
しかしブラウザ上でアプリと同じサービスを旋回できるため、利用障壁がなくなる＝離脱率やCVR改善が考えられます。
メリットにもなるのですが、例えばPWAではなくアプリを開発するとしてこの資料をみてください。

![アプリのインストール数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/85ecad43-bb6a-868d-a932-68b83e728428.png)

> [スマホ利用者に、アプリ利用状況を調査！アプリ課金状況や、インストール個数が明らかに](https://honote.macromill.com/report/20180329/)

アプリであればたくさんのアプリ市場の中で勝ち取りにいく必要があります。
PWAではwebサイトで流入してくるユーザーをアプリへ誘致せずにインストールさせることができるので違う角度からアプローチできています。

### ネイティブアプリのような使用感を手に入れれる。

#### プッシュ通知
webアプリを入れているユーザーにしかプッシュ通知できませんでしたが、PWAを通してプッシュ通知を行うことができるようになりました。
プッシュ通知はメールと違い、URLをクリックするまでの段階が浅くユーザーも早く情報にたどり着けます。
またメールよりもクリック率が3倍ほど高かった実績もあるようです。
そのため接触率が高くなったりリマインド機能としての効果もあり継続して利用してもらう施策としても有効な手段ではないかと思います。

#### オフラインでも操作可能
キャッシュを利用してページを表示させるため、オフラインでもサイトを閲覧することができます。
オフラインでできることってそんなに必要とされているのか？と思われた方もいると思いますが、生活の中で接続が悪い場合や、接続を切らないといけない状況などで活躍します。
一番イメージできるのはgoogleのスプレッドシートやドキュメントもオフラインで操作できオンラインに戻った時データを更新してくれます。

#### デバイスの機能を利用できる
・カメラ
・位置情報
・音声入力
・ジャイロスコープなどのセンサー
などデバイスの機能を利用することができます。

今ではIPアドレスベースでの地域ターゲティングだったのがPWA対応によって、GPSを利用した精度の高い地域ターゲティングを行うことが可能になります。

### 表示速度の高速化
PWAはキャッシュを利用するためページの読み込み速度が早くなります。

## PWAのメリット
PWAでできることを紹介しましたが、PWAを利用することで以下のようなメリットがあります。

### アプリで必要だったリリース審査が不要
ネイティブアプリの場合、リリースするまでに審査があり時間がかかります。
PWAの場合webサイトなので導入障壁もなく最速で実装し、PDCAを回すことができます。

### ユーザーの直帰率を下げられる
ページの表示速度が3秒を越えると直帰率が高まることや、ページの読み込みが1秒増すとユーザーが10%減少するといったデータも存在します。
PWAのサイトは表示速度を高速化できるため一般的なwebサイトよりも直帰率を下げることができる。

### ユーザーと繋がる
本来ではネイティブアプリでしかできなかったプッシュ通知がPWAでは行えます。
例えば一定の間再訪問がないユーザーに対してやキャンペーンを告知することができます。
サイト訪問や購買に繋げることもできる大きなメリットです。

### ネイティブアプリのようなUIにすることができる
・ホームに追加ボタンを表示することができる。~~(UIなのか微妙)~~
・スプラッシュ画面を設定できる
・アプリのように全画面表示ができる


## PWAのデメリット
### アプリとPWAを両方やるとコストがかかる
すでにアプリを運用している場合PWAもアプリのようなユーザー体験を提供するため重複しコストがかかってしまうなと思いました。

### iOSでは一部の機能対応していない

#### データ量が制限されている
オフラインデータは50MBまでに制限がされています。
ユーザーがオフラインで操作する場合は注意が必要

#### プッシュ通知が使えない
プッシュ通知のメリットが重要だと思っている方には残念ですがiOSでは対応していません。

### PWAは普段のweb作業にプラスでついてくるもの
PWAは一般的なコーディング・開発に＋としてPWA対応の作業が乗ってきます。
その分一回におけるリソースが多くなる。

## PWAを導入するためには
ここまでPWAの概要について説明してきましたが、実際にPWAの導入をしていきます。
PWAを導入するにあたって3つの条件があるので紹介していきます。

### HTTPSが必要
PWA対応させるためにはService Workerが必須になります。
ServiceWorkerを使うと改ざんやフィルタリングができてしまうため悪用を避けるためHTTPSを介して提供されるページでしか登録することができません。

### ウェブアプリマニフェストの作成
PWAの基本設定を記述するウェブアプリマニフェスト（JSONファイル）が必要です。
ウェブアプリケーションについて、ウェブアプリをダウンロードしたり、ネイティブアプリと同じように見せたり必要な情報を提供するためです。
詳しくはこちらをご覧ください。
[WebManifest](https://developer.mozilla.org/ja/docs/Web/Manifest)

マニフェストは画像も含めて作成してくれるこちらのサイトがオススメです。
ただし全てをしてくれるわけではないので注意してください。
[Web App Manifest Generator](https://app-manifest.firebaseapp.com/)

実際に自分が書いたコードはこちらです。

```json:manifest.json
{
  "name": "swpractice", 
  "short_name": "swpractice",
  "theme_color": "#4cb7c3",
  "background_color": "#ececec",
  "display": "standalone",
  "Scope": "/",
  "start_url": "/",
  "icons": [
    {
      "src": "images/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
}

```
詳しくは添付したリンクをみて欲しいですが、自分が設定した内容を説明させて下さい。

| 項目 | 意味 |
|:-----------------|------------------|
| name | ウェブアプリケーションの名前をユーザーに表示させる |
| short_name | nameを表示するのに十分にスペースがない場合に使用される。（例えばホーム画面） |
| theme_color | 既存のテーマカラーの定義。これはOSがどうのように表示するかに影響がある。ツールバーとか |
| background_color | スタイルシートが読み込まれる前にアプリケーションの背景色を定義する。スプラッシュ画面の背景 |
| display | ウェブサイトの表示モードを指定する。UIをどう見せるのか |
| Scope | どこまでこのマニフェストを見せるのか制限させる。そのスコープ外にいくと通常のwebサイトに戻る |
| start_url | アプリケーションの開始URLを定義する。ホーム画面のアイコンをタップした時に表示される最初のページ |
| icons | 様々な場面でアイコンとして機能する画像定義 |

といった形です！

### Service Worker

詳しくお話しませんがこのようなソースコードです。

```serviceWorker.js
'use strict';

const CACHE_NAME = 'pwa-v3'; //キャッシュさせる時のキャッシュ名
const urlsToCache = [
  './',
  './index.html',
  './common.css',
  './main.js',
  './manifest.json',
  '/images/index/hapikuru.jpg',
  '/images/icons/icon-144x144.png'
];

self.addEventListener('install', (event) => { //install時
  event.waitUntil(
    caches.open(CACHE_NAME)　//キャッシュを開く
      .then((cache) => {
        return cache.addAll(urlsToCache);　//指定されているリソースをキャッシュに保存させる。
      })
  );
});

// キャッシュcaches.openで開いて、cache.addAllで保存させる。
// event.waitUntilはPromiseをとって、インストールが成功仕方を確認するために使う。
//  ┗https://developer.mozilla.org/ja/docs/Web/API/ExtendableEvent/waitUntil
// ※ファイル数が多くなればなるほどキャッシュが失敗してService Workerがインストールされない確率も高くなる。



self.addEventListener('active', (event) => {
  var cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.map((cacheName) => {  //ホワイトリストにないキャッシュは削除させる。
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName); //キャッシュを消す。
          }
        })
      );
    })
  );
});

self.addEventListener('fetch', (event) => {　//ページの更新などで、Service Workerはfetchイベントを受け取る。
  event.respondWith(
    caches.match(event.request) 
     .then((response) => {　
       if (response) {
         return response;
       }
       
       let fetchRequest = event.request.clone();
       return fetch(fetchRequest)
        .then((response) => {
          if(!response || response.status !== 200 || response.type !== 'basic') {
            //レスポンスが正しいか、レスポンスのステータスが200か、レスポンスの型がbasicか。（リクエストの送信元と送信先のドメインが同じである）
            return response;
          }

          let responseToCache = response.clone();
          cache.open(CACHE_NAME)
            .then((cache) => {
              cache.put(event.request, responseToCache); //リクエストとレスポンスを受け取り指定されたキャッシュへ追加する。
            });
            return response;
        });
     })
  );
});
```

## ServiceWorkerってなに？
ブラウザがwebページとは別にバックグラウンドで実行するスクリプトです。
プッシュ通知やバックグラウンド同期などオフライン対応などがこの人がやってくれています。

僕が学習をしてとても参考になりお世話になった記事を2つ共有させていただきます。

[Service Workerってなんなのよ (Service Workerのえほん)](https://qiita.com/kosamari/items/5e2235d26eb339a33660)
Service Workerの概要がイラスト付きで説明されているので直感的にわかりやすかったです。

[Service Workerの基本とそれを使ってできること](https://qiita.com/y_fujieda/items/f9e765ac9d89ba241154)
Service Workerの扱い方を詳しく説明してくれています。

# まとめ
ここまでPWAとは何か、メリットデメリット、導入方法について、Service Workerについて紹介させていただきました。
ServiceWorkerについてはとても簡潔になってしまい申し訳ございません。
余裕があるときにService Workerについて詳しく記事にしたいと思います。

**PWAはネイティブアプリの代用品となるものではなく、ユーザーがより使いやすくなるようにWebサイトの延長線上にPWAが存在している**と思います。
それが伝われば嬉しいです。



---
ここからは番外編です。

# 自分が作ったものを紹介
こちらです！
https://pwa-delta.vercel.app/
オフラインで試してみて下さい。通知を許可してもらってもいいですが今後もプッシュ通知など勉強で送るので気をつけて下さい・・・

ソースはこちらです。（コミットはまじクソなのでみないでくださいtestしか書いてない）
https://github.com/wrsdu1715/pwa

# push通知を簡単にできるよ
push通知は技術的にちょっと難しいので僕はツールに逃げさせてもらいました（後にチャレンジします）
ちょっとそのツールを紹介させて下さい。
[onesignal](https://onesignal.com/)
こちらは無料で使用できるツールになります。headにCDNを読み込ませるだけでpush通知を送ることもできますし何人が登録しているのかpush通知をクリックした人数なども計測できるのでおすすめです！