どうも、こんにちは。
一人で babel-plugin-macros
タグを占有している者です。
そんな、babel-plugin-macros
は何がすごいのでしょうか?
babel-plugin-macros (babelの作者によるリポジトリ)
Allows you to build simple compile-time libraries
(訳)シンプルな compile-time ライブラリを作れるようにします
compile-timeライブラリとは、
コンパイル時に実行されるライブラリを指しています。
まずは要領を得てもらうために、
penv.macro をご紹介しましょう。
これはNODE_ENV
により「環境ごとの値」に値を分けるコードです。
import env from 'penv.macro'
const BASE_URL = env({
development: 'https://development.example.com',
staging: 'https://staging.example.com',
production: 'https://production.example.com',
})
ええ、普通にパッと見ただけだと、「こんなの誰だって作れるやい!」って思うでしょう。
でも、これは下のようなコードにコンパイルされるんですよ。
const BASE_URL = 'https://production.example.com'
つまり「実行時のオーバーヘッドはない」のです。
しかも、いつも通りimport
するだけで使えるんです。
import env from 'penv.macro'
Webpackで必要になるような細かい設定は必要ないんです。
(もちろん、拡張用の設定手段は提供されているのですが)
もう少し具体的に説明していきます。
なぜbabel-plugin-macros
は生まれたのか
経緯は、こちらの記事にまとめられています。
Zero-config code transformation with babel-plugin-macros
タイトルからもわかるように、
- ゼロコンフィグによるコード変換を行うこと
をミッションにbabel-plugin-macros
は生まれました。
babel は本来、ECMAScriptの基準に達していないブラウザでコードが動作することを目的に作られましたが、
今、それ以上のものなろうとしています。
それは構文拡張ではなく「コード変換」によりもたらされるもので、
- コンパイル時の最適化のために、「コード変換」をカスタマイズするためのライブラリを作る手段を提供しよう!
というのが、babel-plugin-macros
のもたらすものなのです。
もちろん今までも、babel-plugin-xx
によって提供されてきました。
しかし、それには「いくつかの問題」がありました。
- コードを見たときに、そこで「コード変換」が行われていることが明示的でないため、混乱が生じることがあった。
- グローバルな設定が必要で、しかもそれらは
.babelrc
やwebpack
のようなコードの外で行わなければいけない。 - 複数のプラグインが、1度のAST解析の中で同時に行われる。そのせいで衝突が発生したりする。
皆さんは、プラグインの衝突・それらの管理・訳のわからないエラーに悩まされてきたことはないですか?
Gatsby とか Create React App 使ってるから無い?
でも、Gatsby とか Create React App を作っている人たちは悩まされてきたのかもしれません。
だから、彼らもbabel-plugin-macros
を使っているんです。
その証拠に、Gatsby / Create React App 内では、xx.macro
系のライブラリがデフォルトで利用できます。
インストール
でも、それ以外の人たちも、インストールして.babelrc
を設定してあげれば、すぐに使えるようになります。
npm install --save-dev babel-plugin-macros
{
"plugins": ["macros"]
}
簡単ですね。
これだけで、Awesom babel macrosに載っている素晴らしいライブラリが使えるようになるんです。
では、さらにいくつかのユースケースを紹介していきましょう。
コンパイル時にコードを評価する
babel-plugin-preval
に対応するマクロです。
babelの作者がサクッと作ったようです。
import preval from 'preval.macro'
const one = preval`module.exports = 1 + 2 - 1 - 1`
お分かりの通り、1 + 2 - 1 - 1
がコンパイル時に評価され、インラインでコードに埋め込まれます。
別モジュールを評価することもできます。
import preval from 'preval.macro'
const hoge = preval.require('./hoge')
JSON.parse(hoge)
hoge
モジュール内では、hoge.json
を読み込んでいます。
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
できます。
開発中だけ、詳細なコンソールログを出す
これは便利系ですね。ブラウザでもNode.jsでも動きます。
まずは見た方が早そうなので、、、
イイ感じの詳細なログが出ていて、開発が捗りそうです。
こんな「イイ感じの詳細なログ」を出すために、どれだけの苦労をしなければいけないのでしょうか?
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;
}
え?これだけ?って思いませんか?
それがマクロのすごいところなんです。
もちろん、プロダクションコードの実行時にオーバーヘッドなんてありませんよ。
おわり
もっと紹介したいのですが、時間がないので興味がある方は
を見てください。
個人的には、Vue.jsのテンプレートをコンパイルするマクロや、
Jestのマクロでインラインテストコードが書けるようになることを密かに期待しています。
(というか、preval
とかpenv
使えば、できちゃいそうですよね。できたら記事にしますね。)
そんなこんなで、babel-plugin-macros
の紹介でした。
読んでいただき、ありがとうございました。