Madogiwa Blog

主に技術系の学習メモに使っていきます。

esbuild-loaderを使ってwebpackの一部loaderをesbuildに差し替えて高速化するメモ📝

webpackの移行先として、下記の図の通り速度を重視しesbuildが検討されることも多いかと思いますが、

esbuild - An extremely fast JavaScript bundler

webpackを使いつつ一部のbuildをesbuildに置き換えるようなことができるesbuild-loaderというライブラリがあるようなので試してみました。

github.com

前提

いかのようにjsをbabel-loader、tsをts-loaderでbuildするような構成のものを、開発環境でだけ、それぞれesbuildでbuildするようにしてみます。 ※環境別のconfigの切り替えにはwebpack-mergeを利用しています

module: {
    rules: [
      {
        test: /\.(scss|css)/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loader: "ts-loader",
        options: {
          // /vueをtypescriptとして扱う
          appendTsSuffixTo: [/\.vue/],
          transpileOnly: true,
        },
      },
      {
        test: /\.vue/,
        loader: "vue-loader",
        options: {
          loaders: {
            scss: "vue-style-loader!css-loader!sass-loader",
          },
        },
      },
      {
        test: /\.(png|jpe?g|gif)$/i,
        type: "asset/resource",
      },
    ],
  },

webpack configを修正してesbuildに置き換える

以下のようにbabel-loaderとts-loaderをesbuildでのbuild設定で上書きしてあげるだけで大丈夫でした!

process.env.NODE_ENV = "development";

const { merge } = require("webpack-merge");
const common = require("../../webpack.common.js");
const babelLoaderIndex = common.module.rules.findIndex((rule) => rule.use?.loader == "babel-loader");
const tsLoaderIndex = common.module.rules.findIndex((rule) => rule.use?.loader == "ts-loader");

common.module.rules[babelLoaderIndex] = {
  test: /\.js$/,
  exclude: /node_modules/,
  use: {
    loader: "esbuild-loader",
    options: { loader: "js", target: "es2015", sourcemap: true },
  },
};

common.module.rules[tsLoaderIndex] = {
  test: /\.ts$/,
  exclude: /node_modules/,
  use: {
    loader: "esbuild-loader",
    options: { loader: "ts", target: "es2015", sourcemap: true },
  },
};

module.exports = merge(common, {
  mode: process.env.NODE_ENV,
});

改善結果

個人のwebサービス(対象ファイル70ファイル程度)を試しにesbuild-loaderに差し替えてみたところ0.5秒ほど早くなりました🚀 この程度のファイル数でも速度が変わったので大規模サービスの場合には、より明確な差が出そう。

// ts-loader and babel-loader: 最速・最遅を除いた平均 3.953
✨  Done in 3.69s.
✨  Done in 3.85s.
✨  Done in 3.93s.
✨  Done in 4.08s.
✨  Done in 4.31s.


// esbuild-loader: 最速・最遅を除いた平均 3.4833
✨  Done in 3.38s.
✨  Done in 3.47s.
✨  Done in 3.49s.
✨  Done in 3.49s.
✨  Done in 3.59s.

esbuild-loaderはwebpack v4でもテスト実行してるので動きそうですね。

https://github.com/privatenumber/esbuild-loader/blob/v2.19.0/test/loader.test.ts#L12-L15

おわりに

webpackをesbuildに移行せずに一部差し替えてお手軽に高速化できるのは良いですね✨

参考

buildersbox.corp-sansan.com