vue.js&PWAにwebプッシュ通知を適用させてみた

#はじめに
firebase&PWAでのpush通知のサンプルはよく見かけたのですが、
vue-cliで作ったプロジェクトにpush通知を適用するサンプルはなかなか見つからなかったので試行錯誤してみました。
webpackの知識が浅いので、もっと良いやり方あるで！って人はぜひ教えてください。
pushサーバーを作るのは大変そうなので、今回はfirebaseを利用しました。

なお、この記事ではpush通知やらfirebaseやらの細かい仕様は解説しません。

#必要なもの
vue-cli(node,npmなども)
firebaseのアカウント

#ひな形プロジェクト作成

<a href="https://qiita.com/gyarasu/items/2f18edc4ae251180d89e">こちらの記事</a>を参考に作成しました。
最近vue-cli 3がリリースされましたが、今回は2系で作成しました。
なおリンク先では <a href="https://qiita.com/gyarasu/items/2f18edc4ae251180d89e#3-vuejs%E3%81%AEspa%E3%82%92pwa%E5%8C%96%E3%81%99%E3%82%8B">３.Vue.jsのSPAをPWA化する</a> という手順を踏んでいますが、今回はやりません。

出来上がったプロジェクトを`npm run build`すると、`dist`フォルダの中に`service-worker.js`が出来上がっているのが分かります。
この`service-worker.js`にwebpush通知の記述をすればpush通知が動くはずなのですが、
デフォルトだとpush通知の記載がないのでどうにかしてpush通知のコードをこのjsファイルに追記しなければなりません。
build結果のjsに対して直接記述するのはアレなので、設定ファイルを多少いじって工夫します。

#push通知の記述をbuild結果のserviceworkerにマージする
##自前のサービスワーカーを用意
`src`内の`static`フォルダ内にjsファイルを追加します。
ファイル名はなんでもいいのですが、今回は`mysw.js`とします。

```mysw.js
self.addEventListener("push", function(event) {
    event.waitUntil(
      self.registration.pushManager.getSubscription()
        .then(function(subscription) {
          if (subscription) {
            return subscription.endpoint
          }
          throw new Error('User not subscribed')
      })
      .then(function(res) {
        
        return self.registration.showNotification('title', {
          body: 'contents'
        })
      })
    )
})
```

`self.registration.showNotification`の引数はアイコン、タグなど色々ありますが今回は省略します。
##設定ファイルをいじる
ここでいじるのは`webpack.prod.conf.js`です。
SWPrecacheWebpackPluginの部分の記載を下記のように修正します。

```webpack.prod.conf.js
// service worker caching
    new SWPrecacheWebpackPlugin({
      cacheId: 'your-project',
      filename: 'service-worker.js',
      staticFileGlobs: ['dist/**/*.{js,html,css}'],
      minify: true,
      stripPrefix: 'dist/',
      importScripts: ['./static/mysw.js']//この行を追加
    })
```
これによって、デフォルトで出来上がる`service-worker.js`に、自分が書いた`mysw.js`がマージされます。
どうなっているか気になる方は、再度`npm run build`した後の`service-worker.js`ファイルの中を確認してみてください。

ここまでで半分くらいです。続いてはfirebaseと連携する処理を記述していきます。

#firebaseと連携
##firebaseのプロジェクト作成
とりあえずfirebaseであたらしいprojectを作ってみましょう。
<a href="https://console.firebase.google.com/u/0/?hl=ja">firebase</a>にログインして新しいプロジェクトを追加しましょう。
プロジェクトを追加したら、プロジェクトの設定＞クラウド メッセージングタブ内の、
・サーバーキー
・送信者ID
をメモってください。

ここで作成したプロジェクトがpushサーバーの役割を担います。

#ソースコード修正
`manifest.json`,`service-worker-prod.js`を修正します。

```manifest.json
"gcm_sender_id":"送信者ID"//ファイルの最後に←のコードを追加（先ほどメモった送信者IDをここに書く）
```
`service-worker-prod.js`については`window.addEventListener('load', function()`以下を下記の通り修正

```service-worker-prod.js
    window.addEventListener('load', function() {
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register("service-worker.js");
        navigator.serviceWorker.ready.then(function(registration) {
            return registration.pushManager.getSubscription().then(function(subscription) {
              if (subscription) {
                return subscription;
              }
              return registration.pushManager.subscribe({
                userVisibleOnly: true
              })
            })
        }).then(function(subscription) {
            console.log("pushManager endpoint:", subscription.endpoint) 
        }).catch(function(error) {
            console.warn("serviceWorker error:", error)
        })
      }
    });
```
push通知を許可するようにソースを修正しています。
また、subscriptionのendpointをconsole.log出力している処理がありますが、
最後のpush通知に重要な情報を吐き出しています。

ここまでやったらpush通知の準備完了です。

#push通知を試してみる
##資源をhttps対応のサーバーに配置
私はお手軽なgithubPagesを利用しています。
`npm run build`で吐き出されるdist配下の資源をまるっとgithubにpushしてgithubPagesの設定をしてください。
あまり自分はFirebase詳しくないのですが、firebaseは静的資源のホスティングサービスあるみたいなので、そっちでもいいかもです。
##ページにアクセス
ディベロッパーツールを開きながら、該当ページにアクセスしてください。
うまくいっていたらコンソールログに
`pushManager endpoint: https://android.googleapis.com/gcm/send/*endpointの値*`
が出力されているはずです。
このendpointの値は最後のpush通知に必要な値なのでメモってください。
##curlコマンドでpush通知
下記コマンドを叩くとwebにpush通知が届くはずです。

```
curl "https://fcm.googleapis.com/fcm/send" \
     -X POST \
     -H "Content-Type: application/json" \
     -H "Authorization: key=サーバーキー" \
     -d '{
          "notification": {
            "title": "タイトル",
            "body": "本文",
            "click_action": "http://example.com"
          },
          "to": "endpointの値"
        }'
```
今回は簡単のためにcurlコマンドを利用していますが、rest系のクライアントツール、Ajaxでも同様に動きます。

###参考URL
https://qiita.com/gyarasu/items/2f18edc4ae251180d89e
https://qiita.com/keki/items/81634135586763de235a
https://qiita.com/srai0628/items/ebd417b7877295031718