Backpackについて調べた

お手伝いしているプロジェクトで[Backpack](https://github.com/jaredpalmer/backpack)なるものが使われており、はてな？と思ったので調べました。

## Backpackとは？

https://github.com/jaredpalmer/backpack

> Backpack is a minimalistic build system for Node.js projects.

Backpackは、Node.jsのプロジェクトの最小限のビルドシステムだぜ！とのことです。create-react-appやNext.jsにインスピレーションを得たようで、設定ファイルの記述や追加のnpmパッケージなしで、

- Babelによるトランスパイルの実行。async/await、object rest spread、class propertiesなどの構文の利用
- source-mapの対応（source-map-support）
- nodemon的なファイル監視、再実行（Live Reloading）

が、出来るようです。内部ではwebpackを使っているため、webpackが分かるとカスタマイズしやすそう。Backend + webpack = Backpackという由来みたいです。

## インストール

npmパッケージ名は`backpack-core`。ドキュメントでは`--save`（`yarn add backpack-core`）でインストールしているが、用途的に`--save-dev`で問題ないと思う。

```console
# npmの場合
$ npm install --save-dev backpack-core

# yarnの場合
$ yarn add -D backpack-core
```

## CLI

`backpack-core`をインストールすると、`backpack`コマンドが使えるようになります。`backpack`コマンドには、

- `backpack` or `backpack dev`
- `backpack build`

の2種類のサブコマンドしかありません。とてもシンプル！

### `backpack` or `backpack dev`

```console
$ yarn backpack
# または
$ yarn backpack dev
```

開発モード。`backpack`または、`backpack dev`を実行すると、`src/index.js`をエントリポイントとして実行し、ファイルの監視を開始します。（↓の感じの画面）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/18346/c1840aa0-ef2c-ecf8-ed30-60b0ccd60fa9.png)

`backpack dev`で起動した場合は、`__DEV__`に`true`が入るので、開発モードかどうか判定したい場合はそれを使うとよい。`__DEV__`は、webpackのDefinePluginで定義されている。（[ソース](https://github.com/jaredpalmer/backpack/blob/5d6f64e55ece5255846504844531f4f54c0263bd/packages/backpack-core/config/webpack.config.js#L109-L112)）

```js
if (__DEV__) {
  // backpack or backpack devで起動した場合
}
```

babelとwebpackの設定については、カスタマイズできるみたい。

#### Babelの設定のカスタマイズ

プロジェクトルートに`.babelrc`を置くだけ。Backpackの設定を踏襲したい場合は、`presets`に`backpack-core/babel`を追加して、追加したいpresetやpluginをインストール、記述すればよい。

```json:.babelrc
{
  "presets": [
    "backpack-core/babel",
    "stage-0",
    ...
  ]
}
```

`backpack-core/babel`は`babel-preset-backpack`を参照しているだけなので、[babel-preset-backpackのindex.js](https://github.com/jaredpalmer/backpack/blob/edc70c293cdb78c47040298a1e35eb1e859df319/packages/babel-preset-backpack/index.js)を見ると、元々どういう設定なのか把握できる。

#### webpackの設定のカスタマイズ

`backpack.config.js`を作成し、そのファイルの`webpack`フィールドに設定を変更する関数を追加する。

```js:backpack.config.js
module.exports = {
  /**
   * config      -> Backpackのwebpack.config.js
   * options     -> envがあるだけのオブジェクト
   * options.env -> 'development' or 'production'
   * webpack     -> require('webpack')
   */
  webpack: (config, options, webpack) => {
    // カスタマイズする
    ...

    // カスタマイズした設定を返す
    return config;
  }
};
```

また、`backpack.config.js`はBabelのトランスパイルの対象外なので、利用しているNode.jsで使えない構文は書かないように気をつける必要がある。実装を確認してみたが、`backpack.config.js`は`webpack`フィールド以外に設定できる項目がないっぽいです。

### `backpack build`

```console
$ yarn backpack build
```

プロダクション用のビルドを実行。`src/index.js`をエントリポイントにしてバンドルしたファイルを`build/main.js`に出力する。「npmパッケージを全部バンドルしたら大変なサイズにならんか？」と心配になったが、[webpack-node-externals](https://github.com/liady/webpack-node-externals)というnpmパッケージによって、`node_modules`以下のファイルはwebpackの`externals`に指定されており、バンドル後のファイルには含まれない。[ここ](https://github.com/jaredpalmer/backpack/blob/edc70c293cdb78c47040298a1e35eb1e859df319/packages/backpack-core/config/webpack.config.js#L40-L47)にその設定が記述されているが、画像やCSSなどはホワイトリストに入っているので、webpackのloaderを駆使すればJSから操作できるようになりそう。

## おわり

設定や使用方法が本当にミニマムで、すぐ理解できる。Backpack自体の実装もかなりミニマム＆シンプルで、さらっと読める感じなので、Less configurationを突き詰め過ぎて裏で何やっているか分からん、みたいなことは起きない。（これからどんどん機能追加されて辛くなるかもしれないけど）
Node.jsのESのサポートがよくなってもFlowtypeなどを使いたい場合はBabelを入れることになるので、Babelを使うプロジェクトをさっと始めたい場合はかなりよいかもしれない。