Node.js のビルドツール「esbuild」について!


はじめに

esbuild は、キャッシュなしで高速なビルドを可能とする Node.js のビルドツールです。

ビルドツールには、esbuild の他に、Webpack、Gulp、Parcel、Rollup、Browserify、FuseBox などがあります。

私自身が webpack を普段使っていて、ビルドに時間がかかりすぎているのが気になり、esbuild について調べてみようと思いました。

esbuild の特徴としては、

  • キャッシュなしでの高速なビルド
  • ES6 と CommonJS をサポート
  • ES6 の Tree shaking 対応(利用されていないコードの除去)
  • JavaScript と Go による API
  • TypeScript と JSX をサポート
  • ソースマップの生成
  • ソースコードの最小化
  • プラグイン(現在、experimental で v1.0.0 より前に対応予定)

が挙げられます。

この中でも注目すべきは、そのビルド速度にあると思います。

なぜ早いのか?

  1. esbuild は Go で書かれており、ネイティブコードへコンパイルしている

ほとんどのビルドツールは、Javascript によって書かれており、JIT コンパイルを使用するため、速度が遅い。

Go は、並列処理が得意で共有メモリをスレッド間で使用する。また、ヒープメモリも共有している。

よって、CPU を効率的に使用して、並列処理を行える。

  1. 並列で処理を行う

昨今のPCは、複数のメモリを持っているため、効率的に並列処理を行える。

  1. esbuild は、0 から速度を意識して作られた

3rd パーティライブラリを使用するのに比べ、パフォーマンスに対して多くのメリットが得られる。

例えば、多くのバンドラでは、公式の TypeScript コンパイラを使ってパースしているが、そのコンパイラは、パフォーマンスを最優先として作られていない。

その点、0 からパフォーマンスを最優先として作ることで、高速にコンパイルが可能となる。

  1. メモリを効率的に使用する

esbuild は、JavaScript の抽象構文ツリーへは 3 回しかアクセスしない。

また、Go は、コンパクトにしてメモリに保存するため、より効率的にメモリを使用できる。

esbuild の制限

簡単な使い方

$ echo "{}" > package.json
$ yarn add esbuild react react-dom
app.jsx
import * as React from 'react'
import * as Server from 'react-dom/server'

let Greet = () => <h1>Hello, world!</h1>
console.log(Server.renderToString(<Greet />))
$ ./node_modules/.bin/esbuild app.jsx --bundle --outfile=out.js
$ node out.js

速度比較

今回は、create-react-app で作ったアプリケーションのビルド速度を比較します。

通常の React アプリケーション

$ npx create-react-app react-ts-app --template typescript
$ cd react-ts-app
$ vim tsconfig.json
target を es2016 に修正
$ vim src/App.tsx
svg 関連のコードをコメントアウト
$ sudo rm -fr build && /usr/bin/time yarn build

esbuild 版 React アプリケーション

$ npx create-react-app react-ts-app --template typescript
$ cd react-ts-app
$ vim tsconfig.json
target を es2016 に修正
$ vim src/App.tsx
svg 関連のコードをコメントアウト
build.ts
const { argv } = require('process')
const { build } = require('esbuild')
const path = require('path')

const options = {
  define: { 'process.env.NODE_ENV': process.env.NODE_ENV },
  entryPoints: [path.resolve(__dirname, 'src/index.tsx')],
  minify: argv[2] === 'production',
  bundle: true,
  target: 'es2016',
  platform: 'browser',
  outdir: path.resolve(__dirname, 'dist'),
  tsconfig: path.resolve(__dirname, 'tsconfig.json')
}

build(options).catch(err => {
  process.stderr.write(err.stderr)
  process.exit(1)
})
$ sudo rm -fr build && /usr/bin/time node build.ts

結果

通常の React アプリケーション
3.91 real         5.40 user         0.66 sys
3.43 real         5.53 user         0.60 sys
2.96 real         5.25 user         0.57 sys

esbuild 版 React アプリケーション
0.10 real         0.12 user         0.02 sys
0.08 real         0.12 user         0.01 sys
0.08 real         0.12 user         0.01 sys

おわりに

結果を見てもらうと分かるようにかなり高速にビルド出来ました。

create-react-app で作られるアプリケーションには、svg をインポートしている部分がありますが、ここは別途プラグインでやる必要がありそうですが、

今回の目的とは違っていたので、コメントアウトで対応しました。

単純に置き換えるだけではうまくいかないところがあったり、まだ、メジャーバージョンも 1 になっていなかったりするので、様子見しつつ、タイミングを見て導入できればと思います。

開発当初は気にならないほどの速度でビルド出来ていても、開発が進むにつれてだんだんビルドが遅くなり、ストレスに感じることもあるかと思います。

そんな時にぜひ esbuild も検討してみてはいかがでしょうか?

お知らせ

Webサイト・ツール・LP作成のご依頼は、

こちらからお問い合わせいただけます。お気軽にご相談ください。

参考