こんにちは、フロントエンドエンジニアのやなぎ( @apple_yagi )です。
PR TIMESでは、これまでReact/TypeScriptのコードをビルドする際にWebpackを使用していましたが、コード量が増えるごとにビルドにかかる時間が増えてきました。
そこでesbuildを導入し、ビルド時間の短縮に取り組んだのでご紹介いたします。
esbuildとは
esbuildはGo言語で実装されたJavaScript/TypeScriptのビルドツールで、公式ドキュメントには従来のビルドツールと比べて10~100倍速くビルドできると書かれています。
esbuildが提供している主な機能は以下の通りです。(2022/05/30 現在)
- キャッシュなしでの高速なビルド
- ES6 と CommonJS をサポート
- ES6 の Tree shaking 対応(利用されていないコードの除去)
- JavaScript と Go による API
- TypeScript と JSX をサポート
- ソースマップの生成
- ソースコードの最小化
- プラグイン(現在、experimental で v1.0.0 より前に対応予定)
esbuildの導入方法
esbuildはデフォルトで ts, tsx をロードできるため、導入はあまり難しくありませんでした。しかし、PR TIMESではCSS in JSライブラリの Emotion を使用していたり、React17を使用していたため、それらの対応が必要でした。
React17の対応方法についてはesbuildの公式ドキュメントに記載されていたので、簡単に対応することができました。
Emotionについては公式からのアナウンスは、私が探した限りでは見当たらなかったですが、PR TIMESでは esbuild のオプションの jsxFactory と inject を利用して対応しています。
以下はesbuildの設定をTypeScriptで記述したファイルです。(Emotionとは関係のない設定は省略しています)
import { build } from 'esbuild';
import path from 'path';
build({
target: 'es2019',
entryPoints: {
'app': path.join(
__dirname,
'App.tsx',
),
},
outdir: 'dist',
outExtension: { '.js': '.bundle.js' },
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
// React17, Emotion
jsxFactory: 'jsx', // <-- Emotionの JSX Pragma を省略するために設定
inject: ['./emotion-shim.ts'], // <-- jsxのimport文をinjectする
});
import { jsx } from '@emotion/react';
export { jsx };
esbuildを導入した結果
ここから本題のesbuildを導入した結果、ビルド時間は本当に速くなったのかについてです。
結果は以下の通りです。(前項では触れていませんでしたが、esbuild-loaderを使用してビルド時間の短縮も図ってみていたので、一緒に記載します)
ビルド時間(秒) | |
---|---|
Webpack + ts-loader(従来) | 39.85 |
Webpack + esbuild-loader | 28.09 |
esbuild | 2.61 |
ご覧のように、esbuildを導入した結果、従来の Webpack + ts-loader より、約15倍も速くビルドすることができました🎉
また、Webpack + esbuild-loader でもビルド時間が従来よりも11秒ほど速くなってはいましたが、純粋なesbuildの速さには到底及ばない結果となりました。
本記事ではesbuild-loaderの説明は省きますが、こちらのブログで詳しく紹介されているので気になる方はぜひご覧ください。
esbuildでビルドした成果物について
esbuildを用いることで確かにビルド時間の短縮に成功しましたが、ビルド後の成果物に問題がありました。
PR TIMESでは、1つのWebpack、esbuildの設定ファイルで複数のバンドルを生成していますが、その中のいくつかのバンドルのサイズが増加しており、さらに最もサイズが増加したファイルでは以前のバンドルの約15%(100KBほど)増加していることを確認しました。ちなみに、Webpack + esbuild-loader でも esbuild と同じくファイルサイズの増加が見られました。
現状ではこの問題の理由はわかっていないため、esbuildでビルドした成果物は開発環境でのみ使用し、本番環境ではWebpackでビルドした成果物を使用するようにしています。
しかし、開発環境のDXは改善できたため、今回esbuildを導入した目的は果たせたと言えるでしょう。
実際に開発メンバーからも「ビルド待ちの時間ほぼなくなったので、開発のリズムが途切れなくなり集中力を落とさず快適に開発できています!」といった声なども上がっています👏
まとめ
esbuildを使用することでビルド時間を大幅に短縮することができましたが、ビルド後の成果物のファイルサイズの増加を確認したため、Webpackから完全にesbuildへ乗り換えることはできませんでした。
しかし、esbuildはまだメジャーバージョンがリリースされておらず、今後の更なる発展によりこの問題も解決されるかもしれません。今後もesbuildの動向をチェックしたいと思います。