こんにちは,テレビ&ビデオエンターテインメント「ABEMA」で Web エンジニアをしている野口 (@nodaguti) です.今回は,ABEMA の開発組織で行われている「改善week」という制度を使って esbuild というバンドラーを ABEMA Web に導入し,開発ビルドのバンドル処理を最大 69 倍高速化した話をご紹介します.

改善weekとは

ABEMA では事業の成長に合わせて機能開発も活発に行われています.そのため,今でもスプリントごとに新しい機能の追加や既存機能の改善など数多くの施策がリリースされています.

各事業施策は目標としている KPI の達成を目的として設計されています.それゆえに KPI と直接関連しにくい部分のデザイン改善やリファクタリング,開発体験 (DX) 向上などは施策の合間に行う形になりがちでした.また,アニメーションの見直しやアプリの Debug モード整理などといった他チームと連携する必要があるものはタイミングを合わせるのが難しく,提案はされても実際に着手するには乗り越えるべきハードルが高い状況でした.

そこで一年前から,四半期ごとに2週間,開発組織全体で原則として事業施策を全てストップさせ,改善活動に集中する期間として「改善week」が設けられるようになりました.いわゆる20%ルールを一定期間にまとめて確保したようなものです.

一斉に同じ期間で改善を行うようにすることで,チーム横断で取り組む必要のある課題にもアプローチしやすくなっています.また,この取り組みは個々のエンジニアの自主性を尊重し,タスクを割り振るのではなく個人が自ら取り組みたい内容を決める方法で運用されています.

この改善weekでは,Web チームだけでもこれまでに以下のような数多くの改善が実施されました.

  • WAU (Weekly Active Users) などの KPI をグラフィカルにサイネージに表示するとともに,毎朝 Slack にグラフを投稿してくれる「ABEMA NOW」を開発 (w/ デザイナー,分析,インフラチーム)
  • プレイヤーにキーボードショートカットを追加 (w/ デザイナーチーム)
  • フォント指定を見直し,不要な指定を削除/アンチエイリアスを有効化/環境によって絵文字が正しくレンダリングされない問題を修正 (w/ デザイナーチーム)
  • React v16 の deprecated features (UNSAFE_xxx, findDOMNode, Legacy Context API) を使っている箇所をリファクタリング
  • TSLint から ESLint への移行
  • etc…

今回の esbuild 導入も 6/22 – 7/3 にかけて行われた改善weekで実施しました.

esbuild 導入前夜

ABEMA Web では世の例に漏れず webpack を使ってバンドルを行っています. アプリケーション全体のビルドを make build で実行できるようにしているのですが,SSR をしているためバックエンドでも CSS Modules を使ったコンポーネントをビルドできる必要があり,クライアント・バックエンドの両方で webpack によるバンドルが行われます.

その結果,筆者のマシン (1) では client のバンドル処理に約 28 秒,backend に約 12 秒かかり,ビルド全体 (ファイルのコピー, Service Worker スクリプトのビルド,CSS のビルドなどが含まれる) では 84 秒かかっていました (2)

ビルド速度をどうにかより速くできないかと思っていたある日,株式会社カブクの開発者ブログに [Web フロントエンド] esbuild が爆速すぎて webpack / Rollup にはもう戻れない | Kabuku Developers Blog という記事が掲載されました.これによると,rollup からの移行で公称 100 倍,実際の結果として 50 倍の高速化に成功したとのことでした.esbuild の文字通り桁の違う速さが非常に魅力的に感じられ,早速 ABEMA でも導入できないか検討を始めました.

その時点での esbuild は以下のような状況でした.

ES5 未サポート (= IE 未サポート),Browserslist, Code Splitting に対応していないことからプロダクション環境に今すぐ投入するのは厳しそうと判断しました.一方で CSS Modules の件さえなんとかなれば,ローカル開発における webpack に次ぐ第二の選択肢として,実験的に導入するのは可能と考えました.ビルドシステムはアプリケーションには影響しないことから捨てやすく,依存パッケージ増加によるメンテナンスコストの増加もビルド速度の圧倒的向上があれば充分に元が取れます.そして,CSS Modules については 2 年前から脱 CSS Modules を少しづつ進めてきた結果残り 20 ファイルほどまで減っており,今回の改善weekで一気に片付けられそうでした.

以上の検討のもと,実際に esbuild を改善weekで導入してみることを決定しました.

(1): MacBook Pro 13-inch 2017, Dual-Core Intel Core i5 2.3 GHz, RAM 16 GB, macOS 10.15.5.
(2): cache-loader によるキャッシュと -j オプションによる並列並行処理が有効な状態で,5回計測した結果の算術平均.

esbuild 導入の過程

まず CSS Modules を消し去りました.これにより css-loaderpostcss-loader などが消え去り webpack のビルド設定がだいぶすっきりしました ✨

次に webpack.config.js を見ながら esbuild の設定を組み立て, XXX_USE_ESBUILD=true という環境変数が設定された場合に esbuild でバンドルされるようにしました.ABEMA Web ではビルドの設定や埋め込む環境変数を JavaScript ファイルで管理しているので,コマンドを直接叩くのではなく Node API を介してバンドルするようにしました.

このとき,webpack の polyfill により解決されていたと思われる globalprocess.title への不適切なアクセスがエラーとなって発見されたり,Code Splitting/Lazy Loading 未対応に起因した処理順の違いによる問題が発生したりしましたが,いずれも修正は軽微なもので済み,設定の組み立て開始から 2-3 時間で導入に成功しました.

esbuild 導入の結果

導入の結果どれくらい速くなったのか計測するため, time make build -j を 5 回実行して平均を取ってみました.諸条件は以下のとおりです.

  • ビルド設定はローカルビルドを用いて,minify は行わない.
  • コマンド実行用の iTerm2 と記録用の TextEdit 以外のアプリケーションは終了して計測する.
  • webpack (cold build) は node_modules/.cache を毎回削除して cache-loader によるキャッシュがない状態でバンドルした場合を,webpack (hot build) はキャッシュがある状態でのバンドルを,esbuild は esbuild でバンドルを行った場合をそれぞれ表す.
  • Client は client のバンドルにかかった時間,Backend は backend のバンドルにかかった時間,Total は make build 全体にかかった時間 (JS/TS のバンドル以外にファイルのコピー, Service Worker スクリプトのビルド,CSS のビルドなどが含まれる) をそれぞれ表す.
  • 単位は秒.

Client

Client のバンドル処理にかかった平均時間の比較を行うグラフ

# webpack (cold build) webpack (hot build) esbuild
1 83.179 30.729 1.216
2 82.144 27.663 1.185
3 82.026 27.617 1.168
4 82.554 27.135 1.202
5 81.915 28.070 1.194
Ave. 82.3636 28.2428 1.193

クライアントのバンドル処理に限ると,webpack (hot build) に対して esbuild は約 24 倍高速化しました.キャッシュがない場合と比較するとなんと 69 倍です!

Backend

Backend のバンドル処理にかかった平均時間の比較を行うグラフ

# webpack (cold build) webpack (hot build) esbuild
1 39.931 12.611 2.265
2 39.470 11.985 2.392
3 39.697 12.479 2.315
4 38.778 11.913 2.501
5 39.513 12.230 2.205
Ave. 39.4778 12.2436 2.3356

バックエンドのバンドル処理は hot build に対して約 5 倍速くなりました!

Total

Total のビルド処理にかかった平均時間の比較を行うグラフ

# webpack (cold build) webpack (hot build) esbuild
1 183.78 84.17 21.62
2 182.45 84.47 21.57
3 181.82 84.36 21.41
4 183.18 84.37 21.59
5 181.39 84.97 21.38
Ave. 182.524 84.468 21.514

全体では hot build に対して約 4 倍の高速化を達成しました!

おわりに

ビルドの高速化は開発効率の向上につながり,ひいてはより多くの新機能・機能改善をユーザーに届けられるようになります.今回は日頃のリファクタリングによる土台と改善weekというまとまった時間がうまく組み合わさって,タイムリーに改善を行えたよい事例になったのではないかと思います.

ABEMA Web チームでは今後もエンジニアリングにより事業の成長を加速させていきます.よろしくお願いいたします!