Vue.js/JavaScript

アプリケーションの

パフォーマンス最適化

Ryo Utsunomiya(@ryo511)

Ikyu Frontend Meetup

2018-12-12

自己紹介

Agenda

  • 一休.comで実施したパフォーマンス最適化について
  • フロントエンドのパフォーマンス最適化について
  • JavaScriptアプリケーション一般に適用できるパフォーマンス改善手法
  • Vue.jsアプリケーション特有のパフォーマンス改善手法

第1部

一休.comで実施した

パフォーマンス最適化

やったこと

  • スマホ版ホテルページのリニューアル
  • UIは一部変更
    • 再検索は画面遷移ではなく検索結果の再描画に
  • システムは変更点多数

パフォーマンス改善の背景

  • サイトのスピードが遅いという声は以前から上がっていた
  • 遅いサイト = 使いづらいサイトなので、UXの観点からは改善が必要
  • SQLのチューニング等、サーバサイドの最適化はそれなりに実施されてきた
    • ただし、アーキテクチャ的な問題でパフォーマンスが出し切れていなかった
  • フロントエンドの最適化はイマイチで、これが足を引っ張っていた

当時の課題

  • Time To First Byteが遅め(500ms~)
    • 目標値は200ms
  • Render Blocking Scriptsが多い
    • 目標値はゼロ
  • JSのバンドルサイズが大きい(400KB)
    • 目標値は、長期的には170KB、短期的には300KB
  • CSSのサイズが大きく、保守性に問題あり(1万行ほど)
  • 画像のサイズが大きく、lazyloadが不十分

なにをやったのか

  • サーバサイドのフレームワーク差し替え
    • ASP.NET WebForms => ASP.NET MVC
    • フレームワークの移行によって、.NETのasync/awaitをフル活用できるように
    • Solr/SQLのクエリを並行実行してパフォーマンス改善
  • フロントエンドの大幅書き直し
  • imgixを活用した画像最適化
  • 機能・デザインは既存を踏襲し、スコープを広げすぎないように

結果(1) Before/After

※Chrome DevToolsのAuditsを使用、プロファイルはSimulated Fast 3G

結果(2) 競合比較

競合の中で一番速かったBooking.comを

ベンチマークにして改善を実施

最終的にBooking.comよりも速くなった

第2部

Webフロントエンドの

パフォーマンス最適化

パフォーマンス改善のサイクル

  • 計測(+目標設定) => 改善 => 維持のサイクルを回すことが重要
  • ダイエットに似てますね

計測

計測時の注意点

  • 必ずThrottlingしてから計測する
  • Fast 3G = 1.4Mbps
  • 計測環境は毎回同じであることが望ましい(ローカルのChromeよりPageSpeed InsightsやWebPageTestの方がよい)

計測結果の見方(1)

  • まずはスコアを見る
  • 最近LighthouseのScaleが変わって、厳しくなった(以前は75以上で「速い」)
  • スコアは様々なページ・サイトの比較に便利

計測結果の見方(2)

  • 「改善できる項目」と「診断」は超有用
  • ここをベースに改善案を考える

目標設定

  • 最終的なゴールはRAILモデルを参考に
  • Load 1秒以内、Response 100ミリ秒以内、等
  • RAILが現状と乖離しているなら、より近いところに短期目標を置く

他のサイトも計測してみる

  • 他社の同等のページを計測してみると、パフォーマンスの短期目標を立てやすい
  • 一休.comのホテルページの場合、競合で一番速いのはBooking.comのホテルページだった
  • そこで、Booking.comと同等以上のスピードを目標にしてパフォーマンス改善を実施
  • 結果、一休.comのホテルページは、主要なホテル予約サイトでは最速に 💪
  • しかしRAILモデルの目標値には達してない

他サイト計測の注意点

  • 性質の異なるサイトを比べるのはあまり意味が無い
  • サイトの仕様によってチューニングしやすさは変わる
    • コンテンツのリッチさ
    • パーソナライズされたコンテンツの有無
    • 広告、ウィジェット等、サードパーティから読み込むコンテンツの有無

定期的な計測

  • Webサイトのパフォーマンスは、簡単に劣化する
  • 定期的な計測が重要
  • 一休ではCalibreというパフォーマンス計測のSaaSを使って時系列の推移をみている

Performance Budget Alert

  • 定期的な計測に合わせて、パフォーマンス予算のチェックをするのがおすすめ
  • 指標としては、転送するリソースのサイズ、SpeedIndex、Time To Interactive等
  • 予算を超過したらSlackにアラートを流す

第3部

JavaScript/Vue.jsアプリの

パフォーマンス改善

改善ポイントは主に3つ

  • 画像とWebフォントの最適化は費用対効果が良い
  • JavaScriptの最適化は結構大変

速いJavaScriptとは?

  • 速いJS = 少ないJS
  • Webページを表示するまでに読み込まれるjsファイルの総転送量が重要
  • モバイルでは、回線速度を考慮すると170KB(minified/compressed)が上限
    • これより多い場合は「遅い」
  • サイズを意識しないで開発していると、この上限を超えていることが多い。実現可能な短期目標を立てて、少しずつ改善する

速いJavaScriptのための設計

  • JSで書く必要があるか? を常に考える
    • SPAにするより、MPAにしてCDNでキャッシュを効かせる方が速いかも?
  • ライブラリの選定ではサイズを重視する
    • ReactよりPreact、momentよりDay.js等
  • 自前でJSを書かず、チューニング済みのコンポーネントを使う(=AMP)

⚡AMPは速い

JSの最適化ポイント

  • JSの最適化ポイントはいくつかある
    • ロードの最適化、インタラクションの最適化等
  • ロードの最適化が最もクリティカル
  • ロードの最適化のためには、ロード時に読み込まれるJSのサイズをできるだけ減らす必要がある

JSのサイズを減らすために

  • WebpackのCode Splittingで画面ごとにJSを分ける
  • Polyfillを減らす方針を考える
    • PCとモバイルでバンドルを分ける
    • ES Modulesに対応しているかで分ける
    • polyfill.ioを使って配信を最適化する
  • ビルドツール(webpack, Babel等)の最新版を使う
    • メジャーバージョンアップのタイミングで最適化が入ることが多い

precache

  • Service Workerによるprecacheで、JSのダウンロード時間をゼロに
  • 一休.comではWorkboxの導入を検討中
    • AMP版ホテルページで非AMP版ホテルページのアセットをprecache
    • ホテルリストページでホテル詳細ページのアセットをprecache
    • といった用途が想定される

Vue.jsのパフォーマンス

  • Vue.jsは十分に速い
  • 本体のサイズも小さめ(22KB min+gzip)
    • 参考:jquery 30KB, react-dom 30KB
  • Vueコンポーネントのサイズには要注意
    • ミニマムなコンポーネントでも1KBくらいになる

Vueコンポーネントの設計

  • コンポーネントの数が少ない方が、JSのサイズが小さくなる = 速くなる
  • ただし、大きいコンポーネントは保守性が落ちる
  • トレードオフを考えてケースバイケースで対応が必要

条件付きレンダリング

  • v-if
    • false: コンポーネントを描画しない
    • true => false: コンポーネントを破棄
  • v-show
    • false: コンポーネントを描画後、非表示にする
    • true => false: コンポーネントを非表示に
  • デフォルトで非表示の要素はv-ifにすべき
  • 後から非表示にできる要素はv-showがよい
  • 全部v-ifでも、ほとんどのケースで問題ない

非同期コンポーネント

const AComponent =
  () => import('path/to/AComponent');

<button @click="show = true">Lazy</button>
<a-component v-if="show" />
  • Dynamic importを使ってオンデマンドでコンポーネントを読み込む
  • v-ifと組み合わせることで、初期ロード時に不要なコンポーネントをロードしないようにできる(Vueコンポーネントのlazyload)

まとめ

  • Webフロントエンドの最適化のためには、計測・改善・維持のサイクルを回していく必要がある
  • 改善のフェーズでは、細かいチューニングからアーキテクチャ変更まで、様々なスコープの対応が必要
  • パフォーマンス改善には、エンジニアの技術力だけでなく、サービスを開発・運営する組織全体で、UXに意識を高くもつ必要がある

参考文献