イベントの情報サイトをPWAで作ってみた【Nuxt.js】

![mdtakaoka.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/f3f3c11e-ba8c-d079-4273-045c3dc32a9e.png)

# なぜPWAなのか
PWA(Progressive Web Apps)はひと言で説明するとWebがアプリのようになる技術です。
個人的にはとても魅力的な技術だと思うのですが、2015年に発表されてから今まであまり活用されていないような気がします。もちろんネイティブアプリには及ばないですが、情報がまとめてあるのが中心で少しの機能だけの場合はPWAで事足りるのではないかと思ったので作ってみました。

作ったサイトはこちら　https://mdtakaoka.info

まず結論から言うと、Webサイト的には成功したのではないかと僕は思います。下の画像GoogleAnalyticsの解析ですがPWAユーザ（ホーム画面に追加したユーザ）はページ/セッション、平均セッション時間、直帰率がすべてのユーザに比べて良くなりました。今回はWebサイト上にはホーム画面に追加できることを記載しなかったので、１割程度のユーザしかPWAとして利用してくれませんでしたが、記載すればもっと増えたかもしれません。Androidはメッセージが出るのですがSafariだと自分で操作しないといけないのがネックになっているような気がします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/7c902c54-4d99-0c1d-1746-f8b92448f15c.png)


# 構成
Nuxt.jsで構成されており、NetlifyでホスティングしContentfulでコンテンツ管理をしました。
コンテンツ編集者が複数人いたのと、ソースコードの管理とコンテンツ管理を別々にしたかったのでNetlifyCMSは使わずContentfulを使いました。
ソースコードはGitHubで公開しています。
https://github.com/yuta-hayashi/mdtakaoka
以下に工夫点や個人的に便利だったものなどを紹介します。

## Netlify
ホスティングはGitHubとContentfulの連携が簡単なNetlifyを使いました。転送量の無料枠が100GBと広く、速度もそこそこ速いです。
コンテンツの画像はContentfulのサーバからだったので、1ヶ月で7GBでした。
Nuxt.jsではgenerateをしているのですが、これが１分程度かかったのでもう少し早くしたいところです。
generateはGitHubへのPushとContentfulがPublishされたときのWebhockのときにしました。
さらに、Netlifyではプレビュー機能があり、特定のBranchやPullRequestを本番URLに反映させずに見ることが出来ます。身内で確認するときには便利な機能でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/01c46180-cb7e-91c2-340c-8b28287f8037.png)

また、ルートディレクトリに`netlify.toml`を置くことでNetlifyの設定ができます。今回は404の場合にすべて`/index.html`にリダイレクトさせるようにしました。

```toml:netlify.toml
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
```


## Contentful
HeadlessCMSは定番のContentfulです。こちらも無料枠が広く、10人のユーザ、APIリクエスト200万回、転送量750GB、5000個のアセット（記事とメディア）です。最終的に17,000PVでAPIは13,951回、転送量は3.32GBでしたのでかなり余裕がありることが分かりました。画像が結構多かったですが、サイズと品質を指定していたので思ったほど多くなりませんでした。
画像のパラメータに`?fit=thumb&f=top&h=270&w=500&q=80`のようにつけるとそれに合わせた画像が取得できます。
詳しくはContentfulの[ImagesAPIのドキュメント](https://www.contentful.com/developers/docs/references/images-api/)を参考にしてください。

ただ、Contentfulのテキストエディタで日本語の入力がうまく出来ないこと（修正済み？）やモバイルブラウザで動作しないことが欠点かと思います。

## Nuxt.js
### svgで画像を生成
QR-PASSという[QR codeを使って受付するシステム](https://qiita.com/HYuta999/items/8858c062d3a2aaadea8c)を作ったのですが、それをウェブサイト上で印刷できるようにしました。[qrcanvas-vue](https://github.com/gera2ld/qrcanvas-vue)というライブラリを使いQR codeを生成し、そのCanvasをpngにBase encodingし、svgを展開してあるコンポーネントで表示するといった流れです。qrcanvas-vueを使ったのはQr codeの真ん中に画像でロゴが置けるというのが一番の理由です。
チケット画像のsvgはinkscapeで作成し、置き換えたい箇所をvueのデータバインディングで画像や名前のテキストをPropsとして受け取りました。ただ、svgが長いxmlなので扱いづらくもっといい方法があるかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/5a66a810-a393-b29a-d329-ce71e6f700bb.png)
なお、IE,Edgeでは動作しませんでした…

### 画像をキャッシュ
せっかくPWAに対応させているのでContentfulの画像をCashe Storageでキャッシュされるように設定してみました。一応、上限は100個までにしてあります。ただし、サイズはデスクトップやモバイルなど、環境によって違うようです。

```javascript:nuxt.config.js
~省略~
workbox: {
    runtimeCaching: [
      {
        urlPattern: 'https://images.ctfassets.net/\*',
        handler: 'networkFirst',
        strategyOptions: {
          cacheName: 'contentful-assets',
          cacheExpiration: {
            maxEntries: 100,
            maxAgeSeconds: 80000
          }
        }
      }
    ]
  }
~省略~
```

### iOSのセーフエリアの設定
iPhoneX以降では全画面表示したときにホームバーと下のナビゲーションが重なってしまうので、SafariのこのようにCSSでセーフエリア設定する必要があります。
左が設定なしで右がセーフエリアを設定した状態です。

![ios.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/91a449c7-18b8-e3e0-f9ca-746c04226308.png)

```css
  #navigations {
    display: flex;
    text-align: center;
    padding: 0;
    /*セーフエリアの設定*/
    padding-bottom: constant(safe-area-inset-bottom);
    padding-bottom: env(safe-area-inset-bottom);
  }
```
詳しくはこちら
[【iPhoneX対応】webサイトのSafe Area対応（iOS11.1とiOS11.2）](https://qiita.com/kanakana0330@github/items/6ae264b9da00c326ab1d)

### SEO関連
SearchConsoleにドメインを登録し、改善点を探しました。
意外とイベントの正式名ではなく略称で検索されていることがわかったので、ページ内に「MD高岡」のワードを含めることで、表示順位１位になりました。ものすごく単純ですが、SEOはコンテンツを改善するのが一番の策だと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/5cf5290a-4a14-9af9-f14f-4430a24c2803.png)

また、イベントは構造化データをページ内に含めておくことでGoogle検索でリッチリザルトでの表示が期待できます。
https://developers.google.com/search/docs/data-types/event?hl=ja
残念ながら、完全に反映はされませんでしたが、GoogleMapへの表示と検索結果に一部画像だけはモバイル検索で表示されました。
おそらく、新規ドメインであったためと公式サイトではない（あくまでもファンサイト）ためと思われます。

左はモバイルの検索結果、右はGoogleMapアプリでの場所のイベント表示
![Screenshot_20190926-181535_Google.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/78a198d7-ca60-67ee-4e40-b91f81d7cd52.jpeg)




# 余談
先日スターバックスの[公式アプリ](https://www.starbucks.co.jp/mobile-app/)がリリースされたようです。これはポイントやメニュー、近くの店舗を探せるという機能があるようです。
しかし、アメリカのスターバックスもアプリもありますが、PWA版もあるのです！
注文もできるようです。PWAとしてもとても完成度が高いのでぜひ触ってみてください。
https://app.starbucks.com/
試験的にやっているものと思われますが、こういったところからPWA化が進んでいくのではないでしょうか。