コンポーネント読み込みを非同期にして分割したら遅くなった話

こんにちは

自分のプロダクトでは、Laravel+Vue.jsの構成で開発を進めているのですが、
その中のVue.jsで工夫した結果、失敗した事例を記載します。

コンポーネントの遅延読み込み

Vue.jsを使う上で必須とも言えるコンポーネント。
チームでもどうコンポーネントを分けるか、設計するかの議論はよく話題にあがります。
そんな中、コンポーネントの肥大化、また初期表示時での余計なコンポーネントの読み込みによる遅延等が話題となり、その対策の一環として、コンポーネントの非同期読み込みを行って実装を進めていました。

・before

  import MyComponent from './my-component'

  components: {
    MyComponent
  }

・after

  components: {
    MyComponent: () => import('./my-component')
  }

特に、router.jsでは記述がまとまっていることもあり、以下のような状態となっていました。

  path: '/',
  component: DefaultLayout,
  children: [
   {
     path: '/hoge/aaa',
     component: () => import('./views/hoge/Aaa')
   },
   {
     path: '/hoge/bbb',
     component: () => import('./views/hoge/Baa')
   },
// ===== これがサイトにあるページ分続くイメージ ======

速度検証タイム

上記のような形で開発が進んでいき、いざ、環境が揃ったので速度検証しよう!
PageSpeed Insightsで計測したところ・・・

まだ開発途中なのに低くない!?
25秒て!!
と驚きの結果に。
しかし、スコアの割に指摘も少なく、別で原因を探ることに。

速度調査

Chrome DevToolのNetworkにて、ネットワーク帯域を減らし(Fast 3G)
どこに時間がかかっているのかをわかりやすくした上で見た所、
下記画像のようにchunkのjsファイルが大量に読み込まれ、それぞれに0.5s程度かかっていることが判明!

これの原因が、本記事の最初に説明したコンポーネントの非同期読み込みによるものでした。
どうやら、分割することでレイテンシーの積み重ねや、js取得度に走るスクリプトの積み重なりが遅延を生み出してるようでした。

さようなら非同期

対策として、当初行った非同期の記述を全て同期処理に戻して検証してみることにしました。

  components: {
    MyComponent: () => import('./my-component')
  }
  components: {
    MyComponent: require('./my-component').default
  }

結果、PageSpeed Insightsでは以下となりました。

初回読み込みのコンポーネントが大きくなる分、初回ペイントの時間は伸びているものの、
インタラクティブになるまでの時間が大幅に削減され、トータルのスコアも大きく伸びました。
また、Fast 3G環境下でのページ表示速度も体感半分以下、DevToolのNetwork上では5分の1の時間となり、大幅に速度を改善することができました!
システム規模によっては、初回ロードがボトルネックになる場合もあるとは思いますが、本システムだと使わないほうがよさそうという見解となりました。

非同期処理による、体感速度の向上は色々な部分で使われることが多いですが、
一概に早くなるものでもないと実感した事例となりました。

Pocket
LINEで送る