LoginSignup
18
8

More than 3 years have passed since last update.

Ionic/Angularのパフォーマンスチューニング

Last updated at Posted at 2019-07-07

Ionic 4はパフォーマンスを意識した構成となっており、様々な要素からパフォーマンスチューニングを行うことができます。本記事では、Ionic 4のStarter Template(@ionic/angular 4.5.0)をベースとしてパフォーマンスチューニングを行います。

この内容は7月7日のIonic Meetupでの登壇内容です。
https://ionic-jp.connpass.com/event/133896/

Note: Eager Loading は、ModuleをLazy Loadingしないことです。

結論

初期表示について

  • ModuleのEager Loadingにより高速化します
  • Ionic ComponentsのPreLoadにより高速化します
  • Service WorkerのPreFetchは影響がありません

ページ遷移について

  • ModuleをPreLoadによって高速化します
  • Ionic ComponentsのPreLoadによって高速化します
  • Service WorkerのPreFetchにより高速化の可能性あり

未検証

  • rel="preload"によるIonIconの先読み

測定手法

サーバ環境

  • サーバは高機能無料ホスティングサービス「Netlify」
  • Netlifyのサブドメイン
  • Asset optimizationは Disable
  • HTTP/2 Server Pushは未使用

測定

合成モニタリング

株式会社Spelldata 様にご協力いただき、 Catchpoint を使って測定を行いました。Netilyのサーバに近いサンフランシスコを計測ノードに設定。

簡易計測

記事執筆用に、Google Chromeの標準機能についているAudits(Lighthouse)で測定後、 trace より Performance を確認し、そのtime及びレンダリング結果を利用しています。レンダリングがブロックされているなど明らかに差がある場合はこちらを利用しています。

仮説(高速化手法)

1. ModuleをEager Loadingすると速くなる

Angularでは、Module単位でLazy Loadingすることができます。

これにより初期bundleサイズを小さくすることができますので、規模の大きいアプリケーションの高速化に有効です。
反面、JavaScriptファイルを複数呼び出すことになりますので、初期表示に必要なModuleをLazy Loadingすると呼び出しが増えるので遅延している可能性があります。

2. Ionic ComponentsのPreLoad

Ionic ComponentsはすべてLazy Loadingで呼び出すようになっており、呼び出しのタイミングはHTMLファイルもしくはHTMLテンプレートがparseされたタイミングとなります。

ですので、 display: none; で表示せず先にDOMを構成しておけば、PreLoadすることができます。

index.html
  <section style="display: none;">
    <ion-tabs><ion-tab-bar><ion-tab-button></ion-tab-button></ion-tab-bar></ion-tabs>
    <ion-header><ion-toolbar><ion-title></ion-title></ion-toolbar></ion-header>
    <ion-content></ion-content>
    <ion-card><ion-card-header></ion-card-header><ion-card-content></ion-card-content></ion-card>
    <ion-list><ion-list-header><ion-item></ion-item></ion-list-header></ion-list>
    <ion-label></ion-label>
  </section>

このことによって高速化する可能性があります。

3. Service WorkerのPreFetch

@angular/pwa を利用することによって、デフォルトでJavaScriptファイルをPreFetchすることができます。

ng-sw.config.json
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/*.css",
          "/*.js"
        ]
      }
...

このことによって高速化する可能性があります。

検証

初期表示の検証

Starter Templateの Tabs を使って検証しました。ソースコードは https://github.com/ionic-jp/tabs-compare で公開しています。

1. ModuleをEagerLoadingにする

効果がありました。
初期テンプレートのままだと、 Tabs の初期表示は2つのModuleをLazy Loadingする必要があります。

`app.module.ts` => `tabs.module.ts` => `tab1.module.ts`

これをすべて app.module.ts に統合して tabs.module.tstab1.module.ts を削除しました。

ドメイン Mdn名前解決 Mdn レンダリング開始
Default 7.00 697.00
EagerLoading 7.00 683.50(-13.5)

レンダリング開始時間にわずかながら差を確認することができます。また、スピードインデックスにおいては、99パーセンタイルまですべてEagerLoadingがDefaultを速度で上回っていました。

スクリーンショット 2019-06-21 15.04.21.png

2. Ionic ComponentsのPreLoad

効果がありました。

計測上、Defaultを EagerLoading & PreLoad と比較していますが、EagerLoadingのみの時よりも高速化していることがわかります。

ドメイン Mdn名前解決 Mdn レンダリング開始
Default 7.00 697.00
EagerLoading 7.00 683.50(-13.5)
EagerLoading & PreLoad 7.00 637.50(-59.5)

スピードインデックスにおいては、99パーセンタイルまですべてEagerLoading & PreLoadがDefault、EagerLoadingを速度で上回っていました。

スクリーンショット 2019-06-21 14.46.46.png

3. Service WorkerのPreFetch

https://github.com/ionic-jp/tabs-compare/blob/total/src/ngsw-config.json#L10-L12
効果はありませんでした

Service WorkerのPreFetchは、 First meaningful Paint 終了後に実行されます。そのため、Service Workerを有効にしても初期表示への影響はありません。

ページ遷移の検証

1. ModuleをPreLoadする

https://github.com/ionic-jp/blank-preload/blob/preload/src/app/app-routing.module.ts#L12
効果がありました。

遷移先のページをEagerLoadingにすることにより、ページ遷移時の待機時間が削減されます。ただし、冒頭に書いた通りLazy Loadingしないことによりbundleサイズが大きくなるので、初期表示が遅くなる可能性があります。
そのため、 preloadingStrategyPreloadAllModules に設定しておき、遷移前にLoadを完了しておく必要があります。

app-routing.module.ts
@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})

ただし、 PreloadAllModules は事前にLoadするModuleを選択することができませんので、Moduleが多い場合はPreloadするModuleを指定する方が確実にページ遷移の待ち時間を削減することができます。

詳細は Preloading modules in Ionic v4 を参照ください。

2. Ionic ComponentsのPreLoad

https://github.com/ionic-jp/blank-preload/blob/preload/src/app/home/home.page.ts#L12-L21
効果がありました。

しかし、Ionic ComponentsのLoad中は ion-router-outlet が遷移をブロックしますので、 home.html テンプレートに直接書くと /homeの表示が遅くなってしまいます。ですので、TSで非同期にDOMを構築して、PreLoadを行います。

home.page.ts
  ionViewDidEnter() {
    const preloadArea: HTMLElement = document.getElementById('preload');
    preloadArea.appendChild(document.createElement('ion-card'));
    preloadArea.appendChild(document.createElement('ion-card-header'));
    preloadArea.appendChild(document.createElement('ion-card-subtitle'));
    preloadArea.appendChild(document.createElement('ion-card-title'));
    preloadArea.appendChild(document.createElement('ion-card-content'));
    preloadArea.appendChild(document.createElement('ion-back-button'));
  }

上のgifアニメーションがPreloadなし、下がPreloadありとなります。わかりやすいように遷移アニメーションは無効にしています。

blank-default.gif
デモ:https://blank-default.netlify.com

blank-preload.gif
デモ:https://blank-preload.netlify.com

上のgifアニメーションでは、buttonクリック後、2つのJavaScriptファイルを読み込むまで待機しているのに対し、下ではLoad済みなのでクリック直後に遷移していることがわかります。
また、遷移後のIonBackButtonの表示が遅延していないことも確認できます。

3. Service WorkerのPreFetch

効果はある場合があります

しかし、下り30Mbps環境で22000ms程度が必要になります。そのため、ユーザが長時間アプリを操作する場合は、PreFetchによる高速化を期待することができます。

blank-sw.gif
デモ:https://blank-sw.netlify.com/

すべてのファイルのロードに時間がかかるので、オフラインキャッシュの副次的な効果程度に留めておくのがいいでしょう。

未検証だが効果がある可能性の高い施策

rel="preload"によるIconの先読み

ionIcon は、Web ComponentsのRender後に該当するSVGファイルを呼び出し、表示します。
参考コード:https://github.com/ionic-team/ionicons/blob/master/src/components/icon/icon.tsx#L206

そのため、Render以前に利用するSVGファイルを呼び出すると高速化に効果がある可能性があります。

スクリーンショット 2019-06-18 19.39.10.png
(アイコンが表示されないため、Visually Loadedされない)

当初そのように思い、利用する ionIcon もすべて display:none を使ってpreLoadを試しましたが、高速化しませんでした。

デモ:https://tabs-bad-lazy.netlify.com

SVGファイルの呼び出し完了までブロックが発生しているようで異なるアプローチが必要であり、 rel="preload" はそのひとつとして有力です。
iOS/Androidの判定をどうするかといった問題がありますので未検証のままですが、高速化の際にご留意いただけましたら幸いです。

ionImg についても同様です。

まとめ

パフォーマンスチューニングには様々なアプローチがありますが、フロントエンドのエンジニアリングのみで行う場合は「ファイルのリクエストを操作する」、「レンダリングブロックを排除する」のふたつが大きなウェイトを占めることになります。
Developerツールをみながら様々な仮説を立て、検証いただければと思います。

なお、検証結果で差がわずかな場合は、自分自身のネットワーク環境に依存しながら「都合のいい結果」を得ている可能性がありますので、そのような思い込みを排除するためにツールを使った定点観測はとても有用です。

今回、株式会社Spelldata様にご協力いただき利用した Catchpoint は、SPA/PWAを正しく計測できるすばらしいツールですので、ぜひ計測を行う際はご利用をご検討ください。

それでは、また。

18
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
8