babel-plugin-macrosは何がすごいのか

どうも、こんにちは。

一人で `babel-plugin-macros` タグを占有している者です。

そんな、`babel-plugin-macros`は何がすごいのでしょうか？

[babel-plugin-macros （babelの作者によるリポジトリ）](https://github.com/kentcdodds/babel-plugin-macros)

>  Allows you to build simple compile-time libraries 

> （訳）シンプルな **compile-time** ライブラリを作れるようにします

**compile-time**ライブラリとは、

**コンパイル時に実行される**ライブラリを指しています。

まずは要領を得てもらうために、

[penv.macro](https://github.com/chengjianhua/penv.macro) をご紹介しましょう。

これは`NODE_ENV`により「環境ごとの値」に値を分けるコードです。

```javascript
import env from 'penv.macro'

const BASE_URL = env({
  development: 'https://development.example.com',
  staging: 'https://staging.example.com',
  production: 'https://production.example.com',
})
```

ええ、普通にパッと見ただけだと、「こんなの誰だって作れるやい！」って思うでしょう。

でも、これは下のようなコードに**コンパイル**されるんですよ。

```javascript
const BASE_URL = 'https://production.example.com'
```

つまり「実行時のオーバーヘッドはない」のです。

しかも、いつも通り`import`するだけで使えるんです。

```javascript
import env from 'penv.macro'
```

Webpackで必要になるような細かい設定は必要ないんです。

（もちろん、拡張用の設定手段は提供されているのですが）

もう少し具体的に説明していきます。

# なぜ`babel-plugin-macros`は生まれたのか

経緯は、こちらの記事にまとめられています。

[Zero-config code transformation with babel-plugin-macros](https://babeljs.io/blog/2017/09/11/zero-config-with-babel-macros)

タイトルからもわかるように、

- **ゼロコンフィグによるコード変換を行うこと**

をミッションに`babel-plugin-macros`は生まれました。

*babel* は本来、ECMAScriptの基準に達していないブラウザでコードが動作することを目的に作られましたが、

今、**それ以上のもの**なろうとしています。

それは構文拡張ではなく「コード変換」によりもたらされるもので、

- コンパイル時の最適化のために、「コード変換」をカスタマイズするためのライブラリを作る手段を提供しよう！

というのが、`babel-plugin-macros`のもたらすものなのです。

もちろん今までも、`babel-plugin-xx`によって提供されてきました。

しかし、それには「いくつかの問題」がありました。

1. コードを見たときに、そこで「コード変換」が行われていることが明示的でないため、混乱が生じることがあった。
2. グローバルな設定が必要で、しかもそれらは`.babelrc`や`webpack`のような**コードの外**で行わなければいけない。
3. 複数のプラグインが、１度のAST解析の中で同時に行われる。そのせいで衝突が発生したりする。

皆さんは、プラグインの衝突・それらの管理・訳のわからないエラーに悩まされてきたことはないですか？

Gatsby とか Create React App 使ってるから無い？

でも、Gatsby とか Create React App を作っている人たちは悩まされてきたのかもしれません。

だから、彼らも`babel-plugin-macros`を使っているんです。

その証拠に、Gatsby / Create React App 内では、`xx.macro`系のライブラリがデフォルトで利用できます。

### インストール

でも、それ以外の人たちも、インストールして`.babelrc`を設定してあげれば、すぐに使えるようになります。

```bash
npm install --save-dev babel-plugin-macros
```

```json:.babelrc
{
  "plugins": ["macros"]
}
```

簡単ですね。

これだけで、[Awesom babel macros](https://github.com/jgierer12/awesome-babel-macros)に載っている素晴らしいライブラリが使えるようになるんです。

では、さらにいくつかのユースケースを紹介していきましょう。

# コンパイル時にコードを評価する

[preval.macro](https://www.google.com/search?client=safari&rls=en&q=preval.macro&ie=UTF-8&oe=UTF-8)

`babel-plugin-preval`に対応するマクロです。

babelの作者がサクッと作ったようです。

```javascript
import preval from 'preval.macro'

const one = preval`module.exports = 1 + 2 - 1 - 1`
```

お分かりの通り、`1 + 2 - 1 - 1`がコンパイル時に評価され、インラインでコードに埋め込まれます。

別モジュールを評価することもできます。

```javascript
import preval from 'preval.macro'

const hoge = preval.require('./hoge')

JSON.parse(hoge)
```

`hoge`モジュール内では、`hoge.json`を読み込んでいます。

```javascript:hoge.js
const fs = require('fs')
const path = require('path')

const filePath = path.join(__dirname, 'hoge.json')

module.exports = fs.readFileSync(filePath, 'utf8')
```

ここで「ん？？？」と思った方もいるでしょう。

最終的に、フロントエンドで実行されるのに、ファイルが読み込めるの？と。

ええ、なぜなら「コンパイル時に実行される」からです。

つまり`hoge.js`こそが「マクロ」としてコンパイル時に実行されるコードなんです。

評価結果は、JSON文字列なので、`JSON.parse`できます。

# 開発中だけ、詳細なコンソールログを出す

[scope.macro](https://www.npmjs.com/package/scope.macro)

これは便利系ですね。ブラウザでもNode.jsでも動きます。

まずは見た方が早そうなので、、、

![](https://github.com/mattphillips/babel-plugin-console/raw/53536cba919d5be49d4f66d957769c07ca7a4207/assets/add100-chrome.gif)

イイ感じの詳細なログが出ていて、開発が捗りそうです。

こんな「イイ感じの詳細なログ」を出すために、どれだけの苦労をしなければいけないのでしょうか？

```javascript
import scope from 'babel-plugin-console/scope.macro'

function add100(a) {
  const oneHundred = 100

  // ココ
  scope('Add 100 to another number')

  return add(a, oneHundred)
}

function add(a, b) {
  return a + b;
}
```

え？これだけ？って思いませんか？

それがマクロのすごいところなんです。

もちろん、プロダクションコードの実行時にオーバーヘッドなんてありませんよ。

# おわり

もっと紹介したいのですが、時間がないので興味がある方は

[Awesom babel macros](https://github.com/jgierer12/awesome-babel-macros)

を見てください。

個人的には、*Vue.js*のテンプレートをコンパイルするマクロや、

*Jest*のマクロでインラインテストコードが書けるようになることを密かに期待しています。

（というか、`preval`とか`penv`使えば、できちゃいそうですよね。できたら記事にしますね。）

そんなこんなで、`babel-plugin-macros`の紹介でした。

読んでいただき、ありがとうございました。