よく分かってなくてもNuxt.jsでPWAが作れた話


この記事はPWA Advent Calendar 2018の6日目の記事になります。
既視感のあるタイトルですが気にしないでください。

毎年何かしら自分のレベルに合わせて新技術に触れてみる・作ってみるみたいなのを課してるのですが、
今年個人的にチャレンジしてみようと思ったものの1つにPWAがあります。

そこで今回は大した知識が無くともPWAを作ることができた話をしようと思います。
内容として他の皆様と大したことやってないかもですが、こんなんでも形になったぞというのを知ってもらいたいのもあるので温かい目で見てくださいませ。

Reading…

Link: https://reading.yamanoku.net
GitHub: https://github.com/yamanoku/reading/

日頃自分が見ているニュースを集約してまとめてみたらどうなるだろうか、情報の蓄積・可視化みたいなのを考えておりそういうのができないかなと思ってそれを題材にPWAにしてみようと思いました。以下は経緯みたいなやつです。

情報収集ってどうしてる? - YAMALT vol.04

動作イメージ


自分が最近見た20件のニュース×5ページ分にした計100件を表示。
ページ間はページネーションで動きます。

使用技術

API ホスティング フレームワーク
Slack API
AWS API GateWay
Netlify Nuxt.js

Nuxt.jsのプラグイン・モジュールは以下を使用

  • vue-paginate
    • ページネーション。asyncもあって複数で連携できたり、
    • 個人的には色々あるページネーションの中で導入が簡単(な印象)
  • nuxt-community/pwa-module
    • 皆様ご存知のNuxt.jsでPWAにするなら必要になる
    • PWAにしなくともキャッシュ高速化にも使える

あと当初はNuxt1.0で作成していましたが、今年の2.0の発表に合わせてアップデートしました

Nuxt 2でgenerateしたPWAサイトです
https://twitter.com/yamanoku/status/1043119076489318401

フローチャート

図です。

パフォーマンス

lighthouse

  • Device: Emulated Nexus 5X
  • Network throttling: 150 ms TCP RTT, 1,638.4 Kbps throughput (Simulated)
  • CPU throttling: 4x slowdown (Simulated)

上記設定で計測。Perfomance部分は変動ある感じですがだいたいこんな感じ

2018/9/6 計測

2018/12/2 計測

WebPageTest

  • From: Tokyo, Japan - EC2 - Chrome - Cable

上記設定で計測。

2018/9/6 計測

https://www.webpagetest.org/result/180905_90_60fd3b52c101b6aaeb61fda8ac192468/

2018/12/2 計測

https://www.webpagetest.org/result/181202_Q9_0b087ea9b135cf3ee5e8c790e07853a7/

Fixed & Updates

あんまりPWA要素と関係ないかもですが、更新したことなど。

ページネーションをクリックするとスクロール位置が保存されたままになってる

  • 中間くらいまでスクロールした状態で移動するとページ間でその位置のまま
    • position: fixedvhを使っているせい
  • ページが切り替わったときの制御にscrollTopをかませた
NewsList.vue
methods: {
  onPageChange() {
    document.getElementsByClassName('news-list')[0].scrollTop = 0;
  }
}
NewsList.vue
<paginate-links
  for="lists"
  @change="onPageChange" <!-- ここ -->
  :show-step-links="true"
  :limit="2">
</paginate-links>

絵文字がパースされていない

単純にパースしてあげればいいのかなと思ったので、
node-emoji を使いました。

👍👍👍👍👍

ナイトモード実装

21時〜翌6時までの間は自動的に適応するようにしています。
ただカラーをナイトモード用に自制したというよりかは filter: invert(100); を使って
色反転させただけという超シンプルナイトモードです。

defalut.vue
export default {
  mounted() {
    if((new Date()).getHours() >= 21 || (new Date()).getHours() < 6 ) {
      document.body.className += "night-mode";
    }
  },
}
defalut.vue
.night-mode {
  animation: night 2s ease 0s 1 normal;
  animation-fill-mode: forwards;
  background-color: #fff;
}
@keyframes night {
  0% {filter:invert(0);}
  100% {filter:invert(100);}
}

ちなみに、Vue.jsでhtmlとかbodyをマウントするのよくないらしいです。

与えられた要素は単にマウントするポイントとして機能します。Vue 1.x とは異なり、マウントされた要素は、全てのケースで Vue によって生成された DOM に置き換えられます。
従って、ルートインスタンスを<html>または<body>にマウントすることは推奨されません。
https://jp.vuejs.org/v2/api/index.html#el

ページネーションのボタンアクセシビリティ対応

今回ページネーションのライブラリで使用したvue-paginateですが、<a>タグのみでhrefで明確なリンク遷移が明示されていない、リンクとして未完成な状態のままでした。
また、tabindex指定もないのでタブキーでのフォーカスも効かない状態でした。

そこでページネーションのボタン部分をリンク要素としてではなくbuttonタグに変更して、意味あるタグを設置・タブにおけるフォーカスの両方を解消しようと思いました。

ただ、この内容についてIssueで報告する・プルリクエストを提出することを考えた時、個人での運用なのでいつ見てもらえるか・かつ受け入れられるかもわからないという不安がありました。

そこで、リポジトリをforkして自分専用用のモジュールを作ったほうが早いと感じたので、早速対応しました。

https://github.com/yamanoku/vue-paginate

ただ、開閉時のaria-expandedほかWAI-ARIA部分などはまだまだ対応しきれていないので、今後も改良する余地はありそうです(自前実装になる?)。

今後の更新・TODOなど

以下Scrapboxのページにて順次手作業で更新予定です

https://scrapbox.io/yamanoku/Reading…

PWAを作ってみての感想

  • Nuxt.jsにおけるPWA導入が圧倒的にやりやすい・分かりやすいかなと思いました
    • Vue.js依存ですが…
  • PWAだけに限らないですが、何かしら動くものを作ってみると、新しいものがきたらそこから派生してみる・検証することができる
  • まだまだ改善の余地は大きい部分はあるが試行錯誤していろんなことが検証できるのが楽しい
    • こうしたらいいよ的なアドバイスお待ちしております(コメントでもTwitterでも)
  • 今後の派生として、妻を個人Slackに招待して、家族間でのURL共有みたいなのがやれたらいいかなと思っている
    • 妻が結構検索しまくって共有してくれる(育児・買い物・行きたいところ 等)
    • 夫婦間での共有を簡易・履歴として残すようにしたい
  • 自分でPWAを実装してみてAndroid実機で動かせるのがこれまでにない感覚で面白かった
    • ちなみにポートフォリオサイトもPWA化しています
    • GitHub Pagesと紐づけているので、配下のページ(リポジトリ)も自動的にPWA判定になっている?
      • Birthday-Countdown.js など
      • Service Workerがルートディレクトリで設定されているから?
  • 実際にPWAとして使えるものを使ってみたり検証したりしてみる
    • Service Workerがどういう感じで使われているか とか
    • 自分はTwitterはネイティブではなくTwitter Lite(PWA版)のを使うようにしています。
  • 企業の制作実体験記みたいなのが気になりだす(業務内でのノウハウや失敗など)
  • iOSマジお前...となる気持ちがよくわかる

以上になります。ご覧いただきありがとうございました。
明日(12/7)は@_lemon2003_さんになります。

【弊社アドベントカレンダーPR】

最後に宣伝になりますが、私が所属している株式会社GEEKでもアドベントカレンダーをやっております。良ければご覧になってみてください。
自分はこのアドベントカレンダーほか色んな所に出張執筆予定です。

GEEKアドベントカレンダーの次回担当はマークアップエンジニアの大房さんになります。