Babelでカスタムpresetを作る

## TL; DR;
babel preset/pluginインストール＆設定('A`)ﾏﾝﾄﾞｸｾって人は自分用のpreset作ると幸せになれるよ

## はじめに
フロントエンドのプロジェクトを量産していると、毎回初回の環境構築が面倒になってきます。
特にbabelのpresetとかplugin周り。いちいちインストールして`.babelrc`書いてっていう作業が毎回面倒です。
ボイラープレート作っても良かったんですが、まずは作業楽にする1st Stepとしてbabelのsetupを楽にする方法について調査しました。（※ [公式](https://babeljs.io/docs/plugins/#creating-a-preset)を見ると超簡単そうだったので..

## もともとの構成
```json:package.json
  "devDependencies": {
    "babel-plugin-root-import": "^5.1.0",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-preset-env": "^1.6.0",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
  }
```

```json:.babelrc
{
  "env": {
    "development": {
      "presets": [["env", {"targets": {"browsers": ["last 2 versions"]}, "modules": false}], "react", "stage-0"],
      "plugins": [
        "transform-decorators-legacy",
        [ "babel-plugin-root-import", [{
          "rootPathPrefix": "~",
          "rootPathSuffix": "src/js/"
        }]],
        "import-glob",
      ]
    },
    "test": {
      "presets": [["env", {"targets": {"browsers": ["last 2 versions"]}, "modules": "commonjs"}], "react", "stage-0"],
      "plugins": [
        "transform-decorators-legacy",
        [ "babel-plugin-root-import", [{
          "rootPathPrefix": "~",
          "rootPathSuffix": "src/js/"
        }]],
        "import-glob",
      ]
    }
  }
}
```

たったこれだけなんですが、毎回面倒なのでpreset作ります。

## 作ってみる
公式では`module.exports`書くだけで良さそうだったのですが、いろいろ見てみたら[Airbnbのpreset](https://github.com/airbnb/babel-preset-airbnb)の構成が良さげだったので~~丸パクリ~~参考にしました。

### 準備
```shell
mkdir babel-preset-xxxx && cd $_
npm init -y

# 使用するpreset, pluginのインストール
npm i -S babel-preset-env
npm i -S babel-preset-react
npm i -S babel-preset-stage-0
npm i -S babel-plugin-transform-decorators-legacy
npm i -S babel-plugin-root-import
npm i -S babel-plugin-import-glob
```

### 実装
実装はこんな感じ。

```javascript:index.js
'use strict';

module.exports = function buildXXXXPreset(context, options) {
  var modules = (options && (typeof options.modules === 'boolean' || typeof options.modules === 'string')) ? options.modules : false;
  return {
    presets: [
      [require('babel-preset-env').default, {
        targets: { browsers: ['last 2 versions'] },
        modules: modules
      }],
      require.resolve('babel-preset-react'),
      require.resolve('babel-preset-stage-0')
    ],
    plugins: [
      require.resolve('babel-plugin-transform-decorators-legacy'),
      [require('babel-plugin-root-import').default, [{
        rootPathPrefix: '~',
        rootPathSuffix: 'src/js/'
      }]],
      require.resolve('babel-plugin-import-glob')
    ]
  };
};
```
`modules`オプションを受け取って`babel-preset-env`にわたすようにしています。

ちょっとハマった点として、公式とかAirbnbの実装を見ると

```javascript
require('babel-plugin-hogehoge')
```
の形で書いてたんですが、↑の実装を見てもらっても分かる通り

```javascript
// optionあり
[require('babel-plugin-hogehoge').default, { options }]

// optionなし
require.resolve('babel-plugin-hogehoge')
```
の形にしないと動きませんでした。

### publish
あとはgitにpushして、 `npm publish`で終わりです。この辺の手順は今回関係ないので割愛。

## 使ってみる
作成したpresetの使い方は、他のpresetと同じく、

```shell
npm i -D babel-preset-xxxx
```

して、`.babelrc`に

```json:.babelrc
"presets": ["xxxx"]
```

と書けばOKです。超楽ですね。