普段思ったことや、雑記。

Menu & Search

Babelで簡単にECMAScript 2015(ES6)を「練習する」環境を構築する

2016年6月15日

Babel環境でのコーディングはシミュレーションであって、イコールオリジナルのECMAScript 2015ではない

BabelEcma Internationalにより標準化がされていく策定段階の仕様を先取りして記述することができる、トランスパイラである。トランスコンパイルと調べるとあまり良い答えが出てこないが、クロスコンパイラと似たものと考えると良い。クロスコンパイラは異なるプラットフォームへソースコードをコンパイルするものであるが、トランスパイラは同じプラットフォームでも、ソースコードをバージョンが異なるものへコンパイルをする、というものというのが伝わりやすいかもしれない(※自分でもこれが完全にトランスパイラの定義として正解とは思っていないので、適宜調べてください)。

Babelでコンパイルされたコードは、100%オリジナルの環境と同様にコードが動作する保証はない。また、各所で指摘されていることではあるが、BabelでECMAScript 2015をやることが、ECMAScript 2015をそのまま動作する環境でおこなったことと同義とすることとしてはいけない。というわけで、現状だと生のECMAScript 2015を動かす実行環境として適切なのは、Node.jsだろう。自分も普段は主にNode.jsでECMAScript 2015のコードを書いている。

Node.jsはバージョン6.0.0よりECMAScrip 2015の93%のAPIがカバーされた。Node.jsのECMAScript 2015への対応はバージョンを増すごとにカバー率をどんどん上げている。こちらのサイトを参照すると、Node.js 0.12ではECMAScript 2015のカバー率は18%であったが、Node.js 4では50%、Node.js 5では56%、そして現在の最新のNode.js 6では93%となっている(※2016年6月13日現在)。Node.js 6のこの残り7%を多いと見るか少ないと見るかだが、APIカバー率93%はECMAScript 2015をそのまま実行する環境としては、現実的な数字ではないだろうか。

 

Babel環境(CLI)の構築

本記事では、Babel公式サイトのUsing Babelのページを参照しつつ、公式サイトの推奨するセットアップ手順を日本語で紹介する。まずはNode.jsの環境をセットアップする。セットアップできていない人は、必要な環境に応じてセットアップする。WindowsやMacを使っている人は公式サイトからNode.jsの実行環境をダウンロードするもよし、Macの人はhomebrewを使ってもよい。Linux環境の人はnvm(Node Version Manager)を使うとよいかと思う。ここではNode.jsの環境構築は終了していることとして、話を進める。

Node.jsの環境構築が完了している場合、npmコマンドが実行できる。適当にテストディレクトリ、この記事の例では仮にbabelディレクトリを作成したとして、ここで下記のようにコマンドを打ち、Babel 6の実行環境をインストールする。本記事で紹介するコマンドはUbuntu 14.04で実行確認した。なお、実行していくコマンドは基本的には特にコメントされていない場合は、すべてプロジェクトのディレクトリ直下ということとする。

$ mkdir babel
$ cd babel
$ npm init
$ npm install --save-dev babel-cli babel-preset-es2015

インストールしたパッケージのうち、babel-cliはBabelコンパイラのコアパッケージ、babel-preset-es2015がECMAScript 2015のコンパイル設定である。公式のインストール手順でも触れられているが、Babelの環境はnpmのグローバルインストールよりも、プロジェクトごとでのローカルでのインストールが推奨されている。なので、このチュートリアルでもそれにならっている。

次に2点、ちょっとした設定をしてBabelの環境構築は完了である。まず1点目に、package.jsonに加筆をする。加筆する箇所は下記ハイライトした箇所の”build”と描かれている8行目のライン、と7行目の文末のカンマだ。

{
  "name": "babel",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "babel src -d lib"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.10.1",
    "babel-preset-es2015": "^6.9.0"
  }
}

package.jsonのscriptsの箇所は、通称npm-scriptsと呼ばれる。npm-scriptsについては下記の記事がわかりやすいので、詳細は割愛するが、要はnpm-scriptsを使用することで、babelのエイリアスを設定してわかりやすい状態でbabelコマンドを使おう、ということだ。

npm-scriptsについて – Qiita

http://qiita.com/axross/items/a2a0d148e40b66074858

動作確認のため、

# npm-scriptsで指定したコンパイル対象のsrcディレクトリを作成
$ mkdir src
$ npm run build

を実行し、エラーが出ないがないようならBabelの実行環境が準備完了である。

npm run buildをやって「sh: 1: babel: not found」のように怒られる場合

前述の通りにやっていても下記のようにbabelコマンドが見つからない、というエラーが出ることがある。この記事を書くにあたり、セットアップの再現性の確認のために何種類かの環境でセットアップを試してみたが、結構な頻度で遭遇した。

vagrant@vagrant-ubuntu-trusty-64:/vagrant/babel$ npm run build

> [email protected] build /vagrant/babel
> babel src -d lib

sh: 1: babel: not found
npm ERR! Linux 3.13.0-87-generic
npm ERR! argv "/home/vagrant/.nvm/versions/node/v6.2.1/bin/node" "/home/vagrant/.nvm/versions/node/v6.2.1/bin/npm" "run" "build"
npm ERR! node v6.2.1
npm ERR! npm  v3.9.3
...

これはどういうことかというと、文字通り指定した箇所にbabelコマンドの設定がないことが原因なのだが、通常はnpm installをすると、node_modules/.bin配下にコマンドの設定がされる(node_modules/.bin/babelによっては中身は単にスクリプトをrequireしているだけで、エイリアスのように思えた)。なんらかの原因により、babelコマンドのエイリアスが設定されていないことが原因だ。通常、正しい設定の場合にbabel関連の設定状況はこうなっている。

lrwxr-xr-x 1 vagrant vagrant    25 Jun 13 15:11 babel -> ../babel-cli/bin/babel.js
lrwxr-xr-x 1 vagrant vagrant    42 Jun 13 15:11 babel-external-helpers -> ../babel-cli/bin/babel-external-helpers.js
lrwxr-xr-x 1 vagrant vagrant    30 Jun 13 15:11 babel-node -> ../babel-cli/bin/babel-node.js

なので、解決策としては、npm-scriptsに直接babel.jsの位置(node_modules/babel-cli/bin/babel.js)を教えるか、またはチュートリアル通りに設定していくなら、babelコマンドのエイリアス(のようなもの)を自分で設定してやることになる。今回はbabel.jsを直接指定して解決をすることにする。なので、package.jsonはこうなる。

{
  "name": "babel",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "node_modules/babel-cli/bin/babel.js src -d lib"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.10.1",
    "babel-preset-es2015": "^6.9.0"
  }
}

動作確認のため、npm run buildを実行する。エラーが出ない場合はセットアップ成功だ。おそらくセットアップでエラーといえば、babelへのパスが間違っているくらいだと思うので、だいたい解決できることだろう(自分の環境では再現性を確認しているときに何度もこれが出た。他にパターンがあったらむしろ教えてほしい)。

これでBabelの実行環境はbabelディレクトリ配下にセットアップできた。

 

ECMAScript 2015のソースコードをBabelでコンパイルしてみる

さて、実際にECMAScript 2015のコードをコンパイルしてみないと面白くないと思うので、簡単なサンプルコードを用意し、それをコンパイルしてみる。下記のコードをsrcディレクトリにsample.jsとして保存する。

const greeter = (firstName='Masaki', familyName='Miyauchi') => {
  const message = `Hi, ${firstName} ${familyName}!
  Welcome to ECMAScript2015.`;
  return console.log(message);
};

for (let i = 0;i < 3; i ++){
  console.log(`${i+1} times.`);
  if (i == 1) {
    let [firstName,familyName] = ['Sho','Zama'];
    greeter(firstName,familyName);
  } else {
    greeter();
  }
}

内容的には、greeter関数をfor文で3回ループするだけの取るに足らないプログラムであるが、なるべくそこにECMAScript 2015の要素を詰めてみた。ちなみに、ECMAScript 2015の記法で使っているのは下記の5つである。

  • constによる定数宣言
  • letによる変数宣言
  • テンプレート文字列
  • 分割代入
  • 関数の引数デフォルト値

それでは、プロジェクトディレクトリの直下にてやはりnpm run buildを実行する実行するとこのように出力される。

$ npm run build

> [email protected] build /vagrant/babel
> node_modules/babel-cli/bin/babel.js src -d lib

src/sample.js -> lib/sample.js

libディレクトリ配下にsample.jsができたということで、libディレクトリを作っていなくてもプロジェクトディレクトリ直下にlibディレクトリが作成され、そこにコンパイルされたファイルが格納される。sample.jsをコンパイルすると、新たにこのようなsample.jsが生成される。

'use strict';

var greeter = function greeter() {
  var firstName = arguments.length <= 0 || arguments[0] === undefined ? 'Masaki' : arguments[0];
  var familyName = arguments.length <= 1 || arguments[1] === undefined ? 'Miyauchi' : arguments[1];

  var message = 'Hi, ' + firstName + ' ' + familyName + '!\n  Welcome to ECMAScript2015.';
  return console.log(message);
};

for (var i = 0; i < 3; i++) {
  console.log(i + 1 + ' times.');
  if (i == 1) {
    var firstName = 'Sho';
    var familyName = 'Zama';

    greeter(firstName, familyName);
  } else {
    greeter();
  }
}

ご覧のように、Babelでコンパイルされて出てくるコードは可読性は良くはないので、Babelで書き始めたらECMAScript 2015のコードで書き続けて、コンパイルされて出てきたコードはあくまで動作用にする。ということで、Babelによって出力されたコードは実際のところ、見た目的にはあまり気にしてはならないという状態だ。

 

コンパイルされたコードの「見やすさ」でいうなら、BabelよりもTypeScript

コンパイルされたコードの可読性まで気にしだす場合には、TypeScriptがオススメだ。BabelはJavaScript界隈では特に人気があるが、TypeScriptも同様に人気だ。TypeScriptはAngular JS 2.xの開発で採用されているということもあり、その人気に勢いが増している(TypeScriptの開発はMicroSoft、Angular JSの開発はGoogleということで巨塔コンビということで、今後においてもTypeScriptの勢力拡大の可能性を感じる)。 TypeScriptによってコンパイルされたJavaScriptのコードは、Babelよりは可読性が高い。

ただし、TypeScriptはそもそもJavaScriptには良く似ている記法をするが、独自の記法やルールがある上、動作コードはコンパイルが前提、クラスがECMAScript 2015のクラスとは概念が違っていたりする…など、通常のJavaScript環境とは様々な違いがある。なので、TypeScriptを純粋なトランスパイラのBabelと全く同じ分類のツールとして混同してはいけない。TypeScriptは「TypeScriptという言語」で、JavaScriptは似て非なる言語であり、別の言語環境と思っていた方がとっつきやすいと思う。

 

終わりに…

BabelのCLIでのセットアップは、記事中で紹介しているような若干の罠もあり、実際のところは面倒な部類に入る。Gulpだったり、他さまざまなビルドツールなどに慣れている人は、

Using Babel · Babel

https://babeljs.io/docs/setup/

の1の項目にて使用しているツールの手順を選ぶと手順が簡単に出てくるので、無理にCLIを選ぶ必要はなかったりする。僕の場合は、現在フロントエンドのビルドツールを選定途中だったということもあり、フロントエンド開発でのECMASCript 2015環境欲しさにまずはCLIでやってみたということだ。

「ECMAScript 2015入門」のような記事も今後書こうと思うが、この記事でECMAScript 2015学習において、環境構築の面で何か初学者の方の足がかりになればと思う。

mmiyauchi

プログラムを書きながらTranceを聴くのが良いですね。みなさんも聴いたほうがいいですよ、Trance。EDMよりハードトランスでしょ。

Related article

Redux(react-redux)における適切な配列要素の更新

2021年8月23日…

CloudFlareの『SSL/TLS 暗号化モード(HTTPS通信設定)』を使用したとき、『ERR SSL VERSION OR CIPHER MISMATCH』のエラーでChromeで発生し、接続できない場合の対処

英語の記事は見当たっ…

Dart(Flutter)についての所見

Dart(Flutter)についての所見

第一印象では、クロス…

Discussion about this post

コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Type your search keyword, and press enter to search