(node.js) esbuildの開発環境を作成してみた

## やったこと

1. esbuildを試すべく、開発用の環境を用意
2. esbuild watchモードが使い辛かったので改善

## ちゃんと使えたか？
個人開発でクオリティはさておき、ちゃんと動いてくれました。（React×esbuild）
[補助金検索してみようWeb](https://subsidy-support-site.web.app/#/search_page)

## esbuildで困った点
普段webpackでバンドルしていますが、webpackと比較してこんな点、困りました。

### esbuildのwatchモードのログ出力が見辛い
完全に個人の好みかもしれませんが、esbuildのwatchモードのログはJSONな形式で渡されるので、そのままログに出力すると見辛かったです。見易く修正しました。

### 型チェックがない
普段webpackでは型チェックもやってくれていたので、esbuildで使えなくて初めて恩恵を実感しました。いざ開発してデプロイすると案外凡ミスが隠れているものです。これも対処しました。

## 環境
以下の構成で作成しました。

```
visual studio code
    extention: debugger for chrome
Node.js v14.8.0
esbuild v0.8.42
typescript v4.1.3
```

## テンプレート
以下GithubにUploadしました。
[esbuild-js-template](https://github.com/ymuichiro/esbuild-js-template)

## 解説
esbuildはconfigファイルを作らずともバンドルは出来ましたが、やっぱりある程度は設定をしたい所です。調べた所webpack同様にconfigファイルが作れるようなので、以下の通りに作成しました。

*開発用*

```javascript:watch.js
const warningLog = warning => {
  warning.forEach(warn => {
    console.error('warning: ', warn.text);
    console.error('detail: ', warn.detail);
    console.error('path: ', `${warn.location.file}:${warn.location.line}:${warn.location.column}`);
    console.error(' -> ', warn.location.lineText);
  });
};
const errorLog = errors => {
  errors.forEach(err => {
    console.error('error: ', err.text);
    console.error('path: ', `${err.location.file}:${err.location.line}:${err.location.column}`);
    console.error(' -> ', err.location.lineText);
  });
};

require('esbuild')
  .build({
    define: { 'process.env.NODE_ENV': `"${process.env.NODE_ENV}"` },
    target: 'es2015',
    platform: 'browser',
    entryPoints: ['src/app.ts'],
    outdir: 'public',
    color: true,
    bundle: true,
    minify: true,
    sourcemap: true,
    watch: {
      onRebuild: (error, result) => {
        console.log('----------------------------');
        if (error) {
          console.error(new Date().toLocaleString(), ' watch build failed ');
          if (error.warnings) warningLog(error.warnings);
          if (error.errors) errorLog(error.errors);
        } else {
          if (result) {
            console.log(new Date().toLocaleString(), ' watch build succeeded ');
            if (result.warnings) warningLog(result.warnings);
          }
        }
      },
    },
  })
  .catch(error => {
    console.error(JSON.stringify(error, null, 2));
  })
  .then(event => {
    console.log('============================');
    console.log('Compile start... ', new Date().toLocaleDateString());
  });
```

*ビルド用*

```javascript:build.js
require('esbuild')
  .build({
    define: { 'process.env.NODE_ENV': `"${process.env.NODE_ENV}"` },
    target: 'es2015',
    platform: 'browser',
    entryPoints: ['src/app.ts'],
    outdir: 'public',
    color: true,
    bundle: true,
    minify: true,
    sourcemap: false,
  })
  .catch(error => {
    console.error(JSON.stringify(error, null, 2));
  })
  .then(event => {
    console.log('============================');
    console.log('Compile start... ', new Date().toLocaleDateString());
  });
```

esbuildは`require("esbuild").build({})`内に設定を追加すれば設定が出来ます。
注目の点としては`watch`の箇所ですが、webpack -watchと異なり自分で出力を定義してやる必要があります。
そのままの出力だとファイルパスの表示も微妙で使いづらいのでログの表示を整えておきました。

esbuildの実行時はこの作成したjsファイルを実行してやればバンドルを開始出来ます。

まだまだwebpackと異なりエコシステムも弱くユーザーも少ないので大規模な開発には適用出来ないかもしれませんが、個人開発、小型の開発では結構使えるんじゃないかと思われます。