こんにちは! フロントエンドエンジニアのもりやです。
今回はママリのアプリ内で使われている WebView に React.lazy
を導入した結果、初回表示時のパフォーマンスが落ちてしまった事例を紹介します。
React.lazy を入れようと思った動機
ママリでは、アプリ内の一部の画面をA/Bテストしやすくするなどの目的で、リリースが容易な WebView を使っています。
ただ WebView の初回表示が遅いという課題があり、今回パフォーマンス改善に取り組んでいました。
その改善策の1つとして React.lazy
を導入して効果を検証してみました。
React.lazy とは
詳しくは公式ドキュメントの コード分割 – React に書かれていますが、ざっくりいうとファイルを分割して遅延読み込みができる機能です。
ママリで使っている WebView は react-router
でパスごとに表示するページを切り替えていますが、ビルド自体は1つのファイルで出力しています。
(正確には外部ライブラリ用にもう1つ出力しています)
そのため本来表示したいページ以外のデータも含めて全部ダウンロードしないと表示ができない状態でした。
ファイルを分割してダウンロード量を減らせば、初回ロード時のパフォーマンスが上がるのでは、という意図で導入してみました。
初回表示時のパフォーマンス計測方法
Google Chrome の DevTools の Performance タブで計測しました。
また以下の設定もしています。
Fast 3G
にする- 計測時のインターネット回線の混雑状況などによる影響を減らすため
- ある程度遅い方が変化を確認しやすいため
Disable Cache
にチェックを入れる- 初回表示時時のパフォーマンスを改善したいので、キャッシュによる変化をなくすため
React.lazy 導入前
bundle.js
(と外部ライブラリをまとめた vendor.bundle.js
) の読み込みが特に時間がかかっているので、ここを削減しようと考えました。
今回 React.lazy
を導入して bundle.js
を複数のファイルに分割するようにしました。
React.lazy 導入後
結論から言うと、ロードにかかる時間がかえって増加してしまい、初回表示時のパフォーマンスが下がる結果になりました。
bundle.js
自体のサイズは 157KB
→ 51.4KB
に削減され、新たに読み込まれるようになったチャンクデータも合計 14KB
なので読み込む容量自体は減らすことに成功しています。
しかし bundle.js
と vender.bundle.js
の読み込みが終わってからチャンクデータの読み込みが開始されるので、その分遅くなってしまうという結果になってしまいました。
いったんパフォーマンスが落ちていることが確認できた時点で、Revertとリリースして React.lazy
の対応を消しました。
考察
React.lazy
を使った場合、必要な全てのスクリプトが読み込まれ評価された後に、チャンクデータが読み込まれるようです。
なので vendor.bundle.js
の読み込み時間が変わらないと、チャンクしたデータの読み込み分遅くなってしまうという結果になりました。
そもそも vendor.bundle.js
の読み込みにも時間がかかってパフォーマンスが低下しているので、ここの改善の方が重要になりそうです。
また vendor.bundle.js
が十分に小さければ、全体のロード時間が短縮され React.lazy
による改善効果があったかもしれません。
なるべく外部ライブラリを導入しない、というのもパフォーマンスに有効かもしれませんね。
まとめ
React.lazy
を入れることでロード時間が削減できる時間が、どれだけパフォーマンスに良い影響を及ぼすのかを考えて導入する必要がある、という学びを得ました。
今回の外部ライブラリのサイズによる影響のように、環境によって React.lazy
を入れることによる影響は変わってきます。
一概に導入する・しない方が良いとは言えないのが難しいところですが、面白ところでもあると思いました。
最後に、コネヒトではフロントエンドを一緒に改善していただけるエンジニアを募集しています!
付録: ChankLoadError
パフォーマンスと直接関係はないのですが、React.lazy を使うように変更してリリースすると ChunkLoadError
というエラーが発生するようになりました。
文字通り React.lazy
を使って分割したファイルが読み込めないという感じのようです。
件数もユーザー数に対する割合としては非常に少なく、再現は難しい状況でした。 一応、ブラウザの DevTools でネットワークを切断したりすると再現はできるのですが、なぜユーザーの環境で起きているのかは不明でした。
検索しても自動でリロードする対応をすると良いよ、ぐらいの記事しか見つかりませんでした。
結局 React.lazy
を使わないように戻したので、解決はしていません。
想像ではありますが、クライアントのネットワーク環境とかも影響あるかもなので、完全に解決するのは難しいかもしれません。
この記事はShodo (https://shodo.ink) で執筆されました。