ここからはじめる!SPAパフォーマンス改善のアプローチ

この記事はeureka Engineering Advent Calendar 2017 21日目の記事です。
20日目はJamesデーティングレコメンドシステムでした。


はじめに

こんにちは。Pairs JPのエンジニアの太田@s5ot)です。

近頃のWebエンジニアの方々におかれましては、dev.toや阿部寛さんのホームページの驚くべきパフォーマンスに喚起され、高速化への高まりを感じられておられるのではないかとお察しします😇


そんな中でこの記事では、Pairsのスマートフォン版アプリ(SPA)で取り組んだパフォーマンス改善について紹介したいと思います。今回の内容は抜本的な改善というより、費用対効果と結果を得るまでのスピードにフォーカスしたものになります。
SPAのパフォーマンス改善をしたいが具体的にどこから手をつけるのが効果的かわからない、という場合の参考になればうれしいです。


SPAのパフォーマンス改善で費用対効果が高いポイントは

  • リソース取得の改善
  • DOMの破棄・再生成コストを避ける

になると考えます。


それぞれのポイントを

  • ファーストビューの表示速度改善
  • 画面遷移の表示速度改善

という面から見ていきます。


ファーストビューの表示速度改善

ファーストビューでは、ユーザーにとって意味がある表示(First Meaningful Paint)をいち早く届けることが目標です。
Pairsのスマートフォン版アプリでは下記の性能改善により、ファーストビューからのCVRを向上することができました 😊


画像最適化

画像を最適化してサイズ削減し、読み込みを待機する時間を短縮します。
https://developers.google.com/speed/docs/insights/OptimizeImages?hl=ja

ファーストビューCSSのインライン化

ファーストビューで必要なCSSのみを抜き出し、HTMLにインライン化します。
linkタグによる外部CSSファイルのダウンロードはブラウザのレンダリングをブロックしてしまうためです。

ファーストビューで必要なCSSのみを抜き出すにはChromeのDeveloper ToolのAuditからRemove unused CSS rulesをみたり、purifycssのようなツールを使うとよいと思います。

http://blackbe.lt/removing-unused-css-selectors-with-google-chrome-tool/https://github.com/purifycss/purifycss

ファーストビューでは必要ないCSSファイルは非同期ロードする

ファーストビュー以外で必要なCSSファイルもレンダリングをブロックしないように非同期でロードします。
非同期ロードするための標準仕様として preload というものがあります。
https://blog.jxck.io/entries/2016-03-04/preload.html


これを使えば、ブラウザのレンダリングブロックを回避してCSSファイルをダウンロードできます。
ただ残念なことにiOS Safariがまだサポートしていません。。


そこでpreloadのpolyfillであるloadCSSというJSライブラリを使って非同期ロードするようにしました。
https://github.com/filamentgroup/loadCSS

JSファイル・CSSファイルのlong term caching

ビルドするたびにJS/CSSの出力ファイルの名前を一意にすることに加え、Response Headerで強いブラウザキャッシュを指示してファイルが都度ロードされることを避ける手法がlong term cachingです。
ファイルの名前を一意にするには、ファイル名中にハッシュ値を含めたり、一意な値のクエリストリングを付加したりする手段があります。


Webpackにはビルドするファイル名にハッシュ値を簡単に含めることができる機能があります。
https://webpack.js.org/guides/caching/


画面遷移の速度改善

一覧から詳細への遷移、詳細からブラウザバックして一覧を再表示、のような非常によく発生するトランジションでユーザーにストレスを感じさせたくありません。
そこで画面遷移でDOMが破棄・再生成されないように工夫して改善を狙います。


SPAの画面遷移は下記のようにRoutingにより表示するViewが決まり、それまで表示していたViewのDOMを破棄して、新しいViewのDOMを生成して表示する、という流れになります。

込み入った画面になってくるとDOMの生成のコストも大きくなり、画面の切り替えが重くなります。
これを解決するために、関係性が強いViewは裏で先行してロードしてDOMを生成しておくようにします。
Routingから決まるCurrent Viewの表示・非表示をDOMを破棄せずに制御します。
地味ですが、効果は抜群です😊


今後の展望

今回ご紹介した内容はパフォーマンス改善の入り口に過ぎず、さらなる改善のためには抜本的な対応が必要になってきます⚡️

  • code split
  • Service Workerによるリソースの遅延ロード・キャッシング
  • CDNをコンテンツキャッシュに使う
  • クリティカルレンダリングパスの最適化

次回はこれらの取り組みについてもご紹介できればと思います。


性能改善に滾っている、性能改善が三度の飯より好き、俺が性能改善だ、というエンジニアをエウレカでは絶賛募集しております。
ぜひ話を聞かせてください。


明日はSREチームが誇る炎のエンジニア後藤くんの登場です。お楽しみに!


エウレカでは、一緒に働いていただける方を絶賛募集中です。募集中の職種はこちらからご確認ください!皆様のエントリーをお待ちしております!

Recommend

eureka Meetup #01 -Android DroidKaigi再演-を開催しました!

オープンソースライブラリ研究会#3を開催しました