CLOVER🍀

That was when it all began.

はじめてのBabel

前々からちょっと気になっていた、Babelをちょっと試してみることにしました。

Babel

Babelって何?という話ですが、ECMAScript 6(ECMAScript 2015)で書かれたコードを、ECMAScript 5または3の機能だけを使ったコードに変換するものらしいです。
「トランスパイラ」というそうな。

で、今回このBabelを試してみます。

ECMAScript 2015の機能については、Babelのドキュメントと、WEB+DB PRESSを見ながら少し試してみました。

Learn ES2015

WEB+DB PRESS Vol.87

WEB+DB PRESS Vol.87

その他、参考にしたのはこちら。
Babelで始める!モダンJavaScript開発 | HTML5Experts.jp

るびま

Babelを使って次期JavaScript、ES6を体験しよう - アシアルブログ

Babelで始めるES6入門 - to-R

ES6 で書く環境を作る(gulp + Babel 編)

babel6での変更点 Gulp・Webpackの設定

How to get sourcemaps for gulp+babel+browserify+uglify - Stack Overflow

今回は、CLIでの実行と、gulp+Browserifyで試してみたいと思います。

CLI

まずは、コマンドラインでBabelを試してみます。

ドキュメントは、こちら。

CLI

CLI - Usage

インストール。

$ npm install --global babel-cli

なのですが、ドキュメントを見るとグローバルインストールするのは「bad idea」らしいです。

Note: Since it's generally a bad idea to run Babel globally you may want to uninstall the global copy by running npm uninstall --global babel-cli.

https://babeljs.io/docs/usage/cli/

とはいえ、--save-devでbabel-cli/binにあるのは、スクリプトなのですが…?

とりあえず、こんなスクリプトを用意。
app.js

"use strict";

class Calc {
    constructor() {
    }
    add(a, b) {
        return a + b;
    }
}

var calc = new Calc();
console.log("calc.add = " + calc.add(1, 3));

var outputFun = x => console.log(x);
[1, 2, 3, 4, 5].forEach(outputFun);

※「babel-node」で動かす時に、「use strict」の記述が必要でした

babelコマンドでコンパイル後のソースが手に入るようですが…あんまり変わらなかったので実行する方にチェンジ。

babel-nodeコマンドを利用するようです。

$ babel-node app.js
calc.add = 4
1
2
3
4
5

とりあえず、動いてくれました。

gulp+Browserify

続いて、gulpおよびBrowserifyと組み合わせてみます。

ドキュメントでは、gulpおよびBrowserify個々に組み合わせることができる記述があります。

gulp

Browserify

今回は、Browserifyのtransformに与える方向で書いてみました。

つまり、こちらを採用します。
Browserify

では、書いていってみます。

npmプロジェクトを作成。

$ npm init

gulpをグローバルにインストール。

$ npm install -g gulp

「--save-dev」で、いくつかインストール。

$ npm install --save-dev gulp browserify babelify babel-preset-es2015 gulp-load-plugins gulp-util gulp-uglify gulp-sourcemaps vinyl-source-stream vinyl-buffer del

「babelify」がBabelとBrowserifyを合わせるためのモジュールです。その他のgulp-xxxなモジュールやvinyl-xxxなモジュールは、minifyやsoucemap作成などのために追加しています。
「babel-preset-es2015」を追加している理由は、後ほど。

また、ES6の追加機能をブラウザがサポートしていない場合は、Polyfillが必要だそうです。

Polyfill

$ npm install --save babel-polyfill

と、ここまで用意して、ソースコードの作成。
src/main.js

import "babel-polyfill";

import {Calc} from "./calc";

var calc = new Calc();
console.log("calc.add = " + calc.add(1, 3));

var outputFun = x => console.log(x);
[1, 2, 3, 4, 5].forEach(outputFun);

src/calc.js

export class Calc {
    constructor() {
    }
    add(a, b) {
        return a + b;
    }
}

先ほど、babel-nodeで動かしたサンプルを、import/exportを使って2分割してみました。
※babel-nodeでは、うまくimportが動かせませんでした…

また、コメントでご指摘いただいたのですが、babel-polyfillとBrowserifyを組み合わせる場合はアプリケーションのエントリポイントに

require("babel-polyfill");

もしくは

import "babel-polyfill";

と書いておけばよいようです。

To include the polyfill you need to require it at the top of the entry point to your application.

If you are using ES6's import syntax in your application's entry point, you should instead import the polyfill at the top of the entry point to ensure the polyfills are loaded first:

http://babeljs.io/docs/usage/polyfill/

今回はECMAScript 6スタイルにしました。

これらのコードを、Browserify+Babelでビルドするように、gulpの設定ファイルを作成。
gulpfile.js

var gulp = require("gulp");
var $ = require("gulp-load-plugins")();
var browserify = require("browserify");
var babelify = require("babelify");
var source = require("vinyl-source-stream");
var buffer = require("vinyl-buffer");
var del = require("del");

gulp.task("clean", function() {
    del.sync("dist/*")
});

gulp.task("browserify", function() {
    browserify("src/main.js", { debug: true })
        .transform(babelify, { presets: ["es2015"] })
        .bundle()
        .on("error", $.util.log)
        .on("end", function() { $.util.log("browserify compile success."); })
        .pipe(source("app.js"))
        .pipe(buffer())
        .pipe($.uglify())
        .pipe($.sourcemaps.init({ loadMaps: true }))
        .pipe($.sourcemaps.write("./"))
        .pipe(gulp.dest("dist"));
});

gulp.task("default", ["browserify"]);

Browserifyのtransformとして、babelifyを加えているところと、presets-es2015を設定しているところがポイントです。

    browserify("src/main.js", { debug: true })
        .transform(babelify, { presets: ["es2015"] })

「presets-es2015」がないと、gulp-uglifyが失敗し、さらにブラウザ上でうまく動かなくなります…。

babel6での変更点 Gulp・Webpackの設定

How to get sourcemaps for gulp+babel+browserify+uglify - Stack Overflow

これでgulpを実行すると

$ gulp
[19:23:22] Using gulpfile /path/to/gulpfile.js
[19:23:22] Starting 'browserify'...
[19:23:22] Finished 'browserify' after 113 ms
[19:23:22] Starting 'default'...
[19:23:22] Finished 'default' after 12 μs
[19:23:22] browserify compile success.

変換されたJavaScriptが出力されます。

dist/app.js

HTML上では、ビルド後のファイルを読み込むように設定します。

<script src="/dist/app.js"></script>

babel-nodeでimportが動かなかったり、BrowserifyとBabelを合わせた時にだいぶハマりましたが、なんとか動かせました。

ただ、現状のChromeFirefoxだとそこそこES6が動くっぽいので、あんまり実感なかったかも…。