👻

TypeScriptのビルドをesbuildで置き換えてみる

2021/04/26に公開

はじめに

簡単なサンプルプロジェクトを作ったのでこちらに置いておきます:
https://github.com/yuichkun/esbuild-typescript-example

本記事ではnode環境でもともと tsc コマンドでビルドを行なっていた環境から esbuild を使った環境への移行をしたい場合のガイドを書きます。

インストール

npm install -D esbuild

注意点など

TypeScript の項を読んでみるといくつか注意点。

  • TSサポート(.ts .tsx)はデフォルトで入っているので、特別必要なことはない
  • ただし、babelと同じくトランスパイルはしてくれるが、型チェックはしてくれない
    • tsc --noEmit を別で走らせてチェックはした方がよい
  • TSにしか存在しないシンタックスもちゃんと動作する
  • tsconfig.jsonでisolatedModules を有効にする必要がある
    • ファイルごとに並列でビルドするので、ビルド時にimportされたものが型なのか値なのか判別できないらしい
  • tsconfig.jsonでesModuleInterop を有効にする必要がある
    • tscがデフォルトでesmをcommonjsに変換するため
  • 以下は サポートされない
    • emitDecoratorMetadata
      • TSの型情報に依存した出力が必要なため
    • const enum
      • コンパイル時に普通の enum に変換される

tsconfig.jsonについて

esbuild実行時に tsconfig.json を探して、
実行時のパスからディレクトリを上に探索する。

ただし、esbuildは tsconfig.json のうち次のプロパティしか参照しない

  • baseurl
  • extends
  • importsNotUsedAsValues
  • jsxFactory
  • jsxFragmentFactory
  • paths
  • useDefineForClassFields

ほかのプロパティは全て無視される。

tsconfig.jsontarget オプションも無視されるが、
esbuild自体の方の target オプションで指定することができる。

ビルドする

注意点

entryPointsに ./src/* のようなglobパターンを渡すことはできないらしい。

 > error: Could not resolve "./src/*.ts" (glob syntax must be expanded first before passing the paths to esbuild)

こういうエラーが出る。

経緯

この辺のissue で議論があり、globの展開はshellが行なっているので、shell-agnosticにesbuildを保つため、globの展開は自分でやれ とのこと。

スクリプト

./scripts/build.js
const { build } = require('esbuild')
const glob = require('glob')
const entryPoints = glob.sync('./src/**/*.ts')// 適宜読み替えてください

build({
  entryPoints,
  outbase: './src', // outbaseを指定することで指定したディレクトリの構造が出力先ディレクトリに反映されるようになる,
  outdir: './lib', // 出力先ディレクトリ
  platform: 'node', // 'node' 'browser' 'neutral' のいずれかを指定,
  external: [], // バンドルに含めたくないライブラリがある場合は、パッケージ名を文字列で列挙する,
  watch: false // trueにすれば、ファイルを監視して自動で再ビルドしてくれるようになる
})
package.json
- "build": 'tsc'
+ "build": 'node ./scripts/build.js',

これでビルドできるようになる。

トランスパイル速度

サンプルプロジェクトを筆者の手元でトランスパイルした結果

  • tsc: 3.34s
  • esbuild: 0.35s

約9.5倍↑

おまけ

こういうプラグインがあった。
globでのimportを自動でやってくれそう?

https://github.com/thomaschaaf/esbuild-plugin-import-glob

Discussion