T-CREATOR

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

Next.jsのビルドへesbuild-loaderを適応してビルド速度を5%の高速化を実現
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

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

経緯

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

環境

  • Next.js 7.0
  • TypeScript 3.0.3
  • NodeJS 14.17.1

改善結果

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

現在のビルド時間

zsh$ 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でした。

回数ビルド速度
192.51s
294.69s
389.26s
495.16s
593.24s
平均92.97s

変更後

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

回数ビルド速度
186.32s
292.55s
380.49s
490.17s
588.64s
平均87.63s

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

esbuild-loaderの導入

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

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

zsh$ yarn add -D esbuild-loader

next.config.jsの変更

現状について

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

next.config.js

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

javascript# 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を追加して読み込んでいます。

javascript# 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へ下記オプションを追加します。

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

その他

未サポート

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

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

ESBuildMinifyPlugin

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

追加したwebpackの設定

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

ビルド実行

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

consoleTypeError: compilation.getAssets is not a function

webpack5系へ変更

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

consoleTypeError: Cannot read property 'get' of undefined

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

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

参考文献

Github

esbuild-loader-examples/examples/next at master · privatenumber/esbuild-loader-examples

esbuild 公式

esbuild - An extremely fast bundler for the web

記事Article

もっと見る