Babel+Gulpで始めるES6

前提

本記事の内容は以下の環境で行った

  • Debian 8.7
  • nodejs 7.4.0
  • npm 4.1.2

概要

本記事では以下について紹介する

  • JavaScriptの次世代仕様であるES6について
  • Babelを用いたES6コードの変換
  • Gulpを用いたBabelの自動実行

ES6(ECMAScript6またはECMAScript2015)

2015年に策定されたJavaScriptの新仕様。JavaScriptに主に以下のような言語仕様を追加した、次世代のJavaScriptと呼べるもの。

  • classベースによるオブジェクト指向
  • アロー関数
  • ブロックスコープを持つ変数/定数の定義
  • 文字列内での変数展開
  • 分割代入
  • 汎用的な非同期処理

など、他言語の良いところをドンドン取り入れて、現代的になったもの。
なお、ES6についてはご存知の方も多いと思うため、詳細は割愛するので必要に応じてググってください。

ES6の問題点

ES6はあくまでW3Cが策定した標準仕様に過ぎず、それを実装するのは各ブラウザベンダである。
そのため、ブラウザによって実装されている機能、されていない機能がバラバラで、特にモバイル系のブラウザと例によってIEは全体的にES6の対応ができていない。

よって、2017年現在でもES6のコードをそのまま使うのはあまり現実出来ではない問題がある。

Babelとは

そこで登場するのが、Babelというツールである。BabelはES6を含んだJavaScriptコードを、ES5以前(基本的に全てのブラウザで動くコード)に変換してくれるツールだ。

Babelを導入することで、フロントエンジニアは最先端のJavaScriptコードを記述しながら、ビルド時には旧コードに変換してブラウザで実行することで、ES6の問題点を解決することができる。

Babelのインストール

node環境であればBabelのインストールは以下のコマンドでインストールすることができる。

$ sudo npm install babel-cli -g
$ sudo npm install --save-dev babel-preset-es2015 -g

Babelの実行

下記のコードは、ES6の機能のうち幾つかを使用した、特に意味のないコードである。ちなみにこのコードでは、ES6のクラス構文、文字列内での変数展開、アロー関数、ブロックスコープを使っている。

class Human {
  constructor(name) {
    this.name = name;
  }
  greeting() {
    console.log(`Hello, My name is ${this.name}`);
  }
}

let createHuman = (name) => new Human(name);

createHuman('sasaki').greeting();

上記のコード(hoge.js)をbabelを用いて変換する。babelでは、特に指定が無い場合変換結果を標準出力するので、fuga.jsに出力する。

$ babel hoge.js --presets es2015 > fuga.js

変換されたコード(fuga.js)が以下である。

'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Human = function () {
  function Human(name) {
    _classCallCheck(this, Human);

    this.name = name;
  }

  _createClass(Human, [{
    key: 'greeting',
    value: function greeting() {
      console.log('Hello, My name is ' + this.name);
    }
  }]);

  return Human;
}();

var createHuman = function createHuman(name) {
  return new Human(name);
};

createHuman('sasaki').greeting();

Class構文がprototype構文に変換されている所が非常に複雑でわかりづらいが、アロー関数を使用していた部分がfunctionに書き換えられていることは一目瞭然だろう。
全体的にコードの内容及びレイアウトが複雑になってしまうが、変換後のコードはプログラマが読み書きすることは無いので、可読性などは不要である。

変換の前後で実行結果が変わらないことを以下に示す。

$ node hoge.js
Hello, My name is sasaki
$ node fuga.js
Hello, My name is sasaki

Gulpとは

前項で、Babelコマンドを用いてES6のコードを変換できることはわかった。しかし、フロント開発をする際に、コードを修正する度にBabelコマンドを実行するというのは現実的ではない。

そこで、タスクランナーツールのGulpを用いて、Babelの実行を自動化する。Gulpなどのタスクランナーとは、特定のタイミングで特定のタスクを処理してくれるツールのことで、Gruntなどが有名である。

今回は、比較的新しく、タスクの記述が簡単なGulpを導入し、JavaScriptコードが更新される度にBabelを自動実行するタスクをGulpで記述する。

Gulpのインストール

Gulp本体と、GulpからBabelを実行するモジュールをインストールする。

$ npm install --global gulp
$ sudo npm install --save-dev gulp-babel

タスクの記述

Gulpでは、gulpfile.jsというファイルに、JavaScriptの形式でタスクを記述する。Gulp自体については、本記事ではあまり紹介しないので、気になる方は参考ページを参照してください。

今回作成したgulpfileを以下に示す。

var gulp = require('gulp');
var babel = require('gulp-babel');

gulp.task('babel' , function() {
  gulp.src('app/scripts/*.js')
      .pipe(babel({presets: ['es2015']}))
      .pipe(gulp.dest('app/scripts/build/'));
});

gulp.task('watch' , function() {
  gulp.watch('app/scripts/*.js' , ['babel']);
});

gulp.task('default' , ['babel' , 'watch']);

ザックリ説明すると、このgulpfileでは、次のようなタスクを実行する。

「app/scripts/内のjsファイルが更新されたら、Babelで変換してapp/scripts/build/にファイルを作成する」

gulpの実行

今回作成したgulpfileには、ファイル監視のタスクを含めているため、バックグラウンドで動作させたままにするのが望ましい。

$ gulp &

gulpがバックグラウンドで動いている間に、該当のJavaScriptファイルを編集し、保存をした瞬間に、以下のようにgulpがタスクを実行する。

[06:45:19] Starting 'babel'...
[06:45:19] Finished 'babel' after 2.86 ms
[06:45:19] Starting 'babel'...
[06:45:19] Finished 'babel' after 2.3 ms

タスクがきちんと実行され、app/scripts/buildディレクトリの方に変換後のファイルが自動で作成される。ご覧のとおり、1ファイルの変換で系5ミリ秒ほどしかかからないため、プログラマはそれを意識すること無く開発を行うことができる。

なお、本記事とは直接関連は無いが、Gruntとそのプラグインを導入することで、以下のようなことも可能になる。

  • 複数のJavaScriptファイルを1ファイルに結合
  • 結合したファイルをミニファイ
  • ブラウザを再読込

モダンなフロント開発ではJavaScriptのコード量、ファイル数が多くなってくるため、1ファイルにまとめてミニファイすることは必須とも言える。

所感

今回、BabelやGulpを導入した根本的な目的は、ES6でJavaScriptを記述することである。そのため、本項ではES6に関する所感をまとめる。

  • prototypeベースとかいう個人的にまったく受け付けないオブジェクト指向を書かずに済むのは本当に助かる
  • JavaScriptは関数が第一級オブジェクトであるため、頻繁に関数定義を行うので、アロー関数はコードの記述量を大幅に減らせて助かる
  • ブロックスコープに寄って、例えばfor文内だけで有効な変数を宣言できるのは大きい。
  • 文字列内で変数を使いたい時に、チマチマ + を使っていたのが辛かったので今更ながら実装されてよかった。

以上より、今後もES6を使える場面では率先して使いたいし、周りにも布教してBabel,Gulpを用いたモダンな開発を取り入れていきたい。

参考

もうはじめよう、ES6~ECMAScript6の基本構文まとめ(JavaScript)
Babelで始める!モダンJavaScript開発
ドットインストール gulp入門 (全12回)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です