Next.jsのビルドへesbuild-loaderを適応してビルド速度を5%の高速化を実現

TypeScriptNext.jswebpackパフォーマンス
Next.jsのビルドへesbuild-loaderを適応してビルド速度を5%の高速化を実現
Memo

Next.jsのビルドへesbuild-loaderを適応してビルド速度を5%の高速化を実現したためメモしました。

経緯

ビルド時間の高速化をはかりたく試してみたところ改善することが出来たため 導入することにしました。

環境

  • Next.js 7.0
  • TypeScript 3.0.3
  • NodeJS 14.17.1

改善結果

先に改善結果から共有します。

現在のビルド時間

terminal
$ time yarn build yarn run v1.22.10 $ NODE_ENV=production next build src // 中略 ✨ Done in 88.85s. yarn build 92.51s user 3.76s system 107% cpu 1:29.19 total

5回実施した平均値

変更前

5回実施して平均は92.97sでした。

回数 ビルド速度
1 92.51s
2 94.69s
3 89.26s
4 95.16s
5 93.24s
平均 92.97s

変更後

5回実施して平均は87.63sでした。

回数 ビルド速度
1 86.32s
2 92.55s
3 80.49s
4 90.17s
5 88.64s
平均 87.63s

約5%のビルド速度の改善効果が得られました。

esbuild-loaderの導入

esbuild-loaderパッケージのインストール

esbuild-loaderパッケージをインストールします。

terminal
$ yarn add -D esbuild-loader

next.config.jsの変更

現状について

Next.jsバージョン7系のプロジェクトでTypeScriptを利用しています。

next.config.js

next.config.jsのwebpackの設定です。

next.config.js
module.exports = withTypescript({ webpack(config, options) { config.plugins.push(new webpack.EnvironmentPlugin(process.env)); if (options.isServer) { config.plugins.push( new ForkTsCheckerWebpackPlugin({ tsconfig: path.resolve("./tsconfig.json"), memoryLimit: 1024 }) ); } if (process.env.NODE_ENV && process.env.NODE_ENV === "production") { config.optimization.minimize = true; config.optimization.minimizer = [ new TerserPlugin({ terserOptions: { compress: { drop_console: true } }, extractComments: "all" }) ]; } return config; } })

変更後

useEsbuildLoaderを追加して読み込んでいます。

next.config.js
function useEsbuildLoader(config, options) { const jsLoader = config.module.rules.find( rule => rule.test && rule.test.test(".js") ); if (jsLoader) { jsLoader.use.loader = "esbuild-loader"; jsLoader.use.options = options; } } module.exports = withTypescript({ webpack(config, options) { config.plugins.push(new webpack.EnvironmentPlugin(process.env)); config.plugins.push( new webpack.ProvidePlugin({ React: "react" }) ); useEsbuildLoader(config, { loader: "tsx", target: "es2017" }); if (options.isServer) { config.plugins.push( new ForkTsCheckerWebpackPlugin({ tsconfig: path.resolve("./tsconfig.json"), memoryLimit: 1024 }) ); } if (process.env.NODE_ENV && process.env.NODE_ENV === "production") { config.optimization.minimize = true; config.optimization.minimizer = [ new TerserPlugin({ terserOptions: { compress: { drop_console: true } }, extractComments: "all" }) ]; } return config; } })

tsconfig.jsonの追記

tsconfig.jsonへ下記オプションを追加します。

tsconfig.json
"isolatedModules": true, "esModuleInterop": true

その他

未サポート

tsconfigの下記のオプションはサポートされていないようです。

  • emitDecoratorMetadata
    • TSの型情報に依存した出力が必要なため
  • const enum
    • コンパイル時に普通の enum に変換される

ESBuildMinifyPlugin

TerserPlugin→ESBuildMinifyPluginを試したのですがビルド時に下記のエラーのため
適応できませんでした。

追加したwebpackの設定

next.config.js
config.optimization.minimize = true; config.optimization.minimizer = [new ESBuildMinifyPlugin()];

ビルド実行

ビルド実行時に下記エラー

TypeError: compilation.getAssets is not a function

webpack5系へ変更

webpackのバージョンが古いためエラーが出ているケースがある記事を参考にwebpackを最新にしてみましたが下記エラーが発生しました。

TypeError: Cannot read property 'get' of undefined

引き続きエラーの原因調査し解決したら記事にしようと思います。

エラーを修正してESBuildMinifyPluginへ置き換えられるともう少し早くなりそうです。

参考文献

Github

esbuild 公式

esbuild - An extremely fast JavaScript bundler

終わりに

最後までご覧いただきありがとうございます。
この記事ではNext.jsのビルドへesbuild-loaderを適応してビルド速度を5%の高速化を実現について紹介させていただきました。

これからも皆様の開発に役立つ情報を提供していきたいと考えています。
今後ともよろしくお願いいたします。