【５分でなんとなく理解！】Babel入門

5分でなんとなく理解するシリーズ、[前回のWebpack入門](http://qiita.com/Shagamii/items/698a67bab0cd5eefcb4f)に続き、第２回はBabel入門です！

# はじめに
この記事は、理科大AdventCalendar23日目の予定だったものです！
このAdvent Calendarの作成者にも関わらず、間に合わなくてすみません！:bow:

僕は、この理科大AdventCalendarで先に投稿していただいた[katsuyukiさん](https://qiita.com/katsuyuki/items/42b3c69bcd76c44ad64a)と[gangunさん](https://qiita.com/gangun/items/ae95b53d229e990b7b12)がおっしゃっていた今はなきi科のあと誕生したI科こと情報工学科の一期生で２年生です！
理科大生を中心とした[学生団体Unitus](unitus.tech)で活動したり、ベンチャーでインターンをさせていただいたり、[Nihonbashi.js](https://nihonbashi-js.connpass.com/)という勉強会を第２回から企画・運営をさせていただいてます。

AdventCalendarということで自分しか書けない記事を書きたいと思っていたのですが、４ヶ月以上７割完成のまま放置されていた記事があったのでとりあえず供養しようと思います。

# Babelとは<img src="https://qiita-image-store.s3.amazonaws.com/0/129548/1d3475be-9405-25aa-c8c1-5ac8e0b5dc04.png" width="90px">
[Babel](https://github.com/babel/babel)とは、簡潔にいうと、JavaScriptのコードを新しい書き方から古い書き方へと変換するツールです。

# なんでコードを変換しないといけないの？
JavaScriptは[EcmaScript](https://ja.wikipedia.org/wiki/ECMAScript)で定められた仕様にしたがって実装されています。
現在、es6と呼ばれる6番目のバージョンまで策定が完了しており、es7が策定中となっています。
そのため、現在エンジニアによって書かれているコードは主にes6がメインとなっているのですが、[各ブラウザで実装されていないes6の仕様が多くあります](https://kangax.github.io/compat-table/es6/)。
また、[Node.jsで実行する際もバージョンによって実行できる仕様が異なります](http://node.green/)。
そのため、ブラウザで使用するまたは、実行環境として考えられるNode.jsのバージョンが定まっていない場合、それぞれの環境で実行するためにそれぞれの環境に合わせてes5の記法に変換する必要があります。


# いろいろなビルドツールとの組み合わせ
babelは単体で使用されることもありますが、様々な種類のビルドツールとの組み合わせで使われることが多いです。
ビルドツールとは、様々な環境に合わせて、モジュールの依存解決、ファイルのトランスパイル、圧縮などを行いやすくするツールと考えてもらえればいいと思います。
ビルドツールでファイルをまとめる時に、babelで変換もする、そんな感じです。
ビルドツールの中でも、[前回紹介した](https://qiita.com/Shagamii/items/698a67bab0cd5eefcb4f)[Webpack](https://github.com/webpack)や、さらに機能が広範囲に及ぶ[browserify](https://github.com/browserify/browserify)、[gulp](https://github.com/gulpjs/gulp)など種類はさまざまです。
最近では、parcelと呼ばれるツールも誕生しました。筆者も軽く使ってみましたが、ほとんど設定ファイルも書かずに手軽に実行できるので便利です。

また、使用用途によって技術選定をするわけですが、今回のサンプルでは、個人的に使い慣れていて、parcel出てきても開発ではまだまだ使いそうという理由で、Webpackを用いています。
[ビルドツールについてより詳しく知りたい方](https://blog.fenrir-inc.com/jp/2016/10/taskrunner-strength-weakness.html)

# 様々な機能
### 様々なplugin
pluginで設定することで、es6で定められたそれぞれの仕様に対して、それぞれ変換することができます。

###  様々なpresets
babelでは、様々presetsを導入することができ、例えば、変換すると同時にflowのために書いた型を取り除いてくれる「flow」や、
できる限り最新のes関連のpresetsまでを含むもしくは、指定したNode.js、ブラウザのバージョンまで必要なpluginをインストールする「env」などがあります。
[主なplugin、presets](https://babeljs.io/docs/plugins/)

# 実行手順
## babelのみの場合
1. node.jsの実行環境を整える
2. babel-cliをインストール
3. plugin、presetsをインストール
4. .babelrcに[設定](https://github.com/Shagamii/babel-introduction/blob/master/only-babel/.babelrc)を書く 

## babel+Webpackで動かす場合
1. node.jsの実行環境を整える
2. babel-loader,babel-coreをインストール
3. plugin、presetsをインストール
4. Webpackのmoduleにbabelの[設定](https://github.com/Shagamii/babel-introduction/blob/master/with-webpack/webpack.config.js)を書く
5. .babelrcに設定を書く

.babelrcを書かずにbabelの実行時にコマンドオプションとして使う方法や、webpackに直接書く方法もあります。

実際に動かすコマンドに関しては以下のリンクをなどを参考にしてみてください。
[babelの実行手順についてもっと知る](https://mae.chab.in/archives/2845)

# どんなふうにうごくの？
それではサンプルコードを用いて動きを確認してみましょう。
## bebelのみの場合
ディレクトリ構造は以下のようになっています。

```
.
├── .babelrc
├── output
│   └── index.js
├── package.json
└── src
    └── index.js
```

babelrcは以下のようになリます。今回はpresetsでenvを使用しました。

```text:.babelrc
{
   "presets": ["env"]
}
```

### サンプルコードを動かす

```js:src:index.js
class Caluculator {
  constructor(initialvalue) {
      this.value = initialvalue

      this.increment = this.increment.bind(this)
  }

  increment() {
      return this.value + 1
  }
}

console.log('before:', 0);
console.log('***increment***');

const increment = new Caluculator(0).increment()

console.log('after:', increment);

```

```shell:実行コマンド
babel src -d output
```

以下がbabelを通した後になります。

```js:output:index.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 Caluculator = function () {
    function Caluculator(initialvalue) {
        _classCallCheck(this, Caluculator);

        this.value = initialvalue;

        this.increment = this.increment.bind(this);
    }

    _createClass(Caluculator, [{
        key: 'increment',
        value: function increment() {
            return this.value + 1;
        }
    }]);

    return Caluculator;
}();

console.log('before:', 0);
console.log('***increment***');

var increment = new Caluculator(0).increment();

console.log('after:', increment);
```
es6の記法がes5の記法に変換されているのがわかりますね。

## webpackを用いた場合
ディレクトリ構造は以下のようになります。

```
.
├── .babelrc
├── entry.js
├── modules
│   └── increment.js
├── output
│   └── bundle.js
├── package.json
└── webpack.config.js
```

.babelrcはbabelのみの場合と同じです。

webpackの設定ファイルは以下のようになります。

```js:weback.config.js
const webpack = require('webpack');

module.exports = {
  target: 'node',
  entry: './entry.js', // entry pointを起点にバンドルしていきます
  output: { // 出力に関して
    filename: 'bundle.js', // 出力するファイル名
    path: `${__dirname}/output/` // 出力するディレクトリ階層
    // pathは絶対パスで指定、そのため __dirname でディレクトリ階層を取得しています
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/, // babelを通さないディレクトリ
        loader: "babel-loader",
      }
    ]
  }
};

```

### サンプルコードを動かす

```js:entry.js
import Caluculator from './modules/increment';

console.log('before:', 0);
console.log('***increment***');

const increment = new Caluculator(0).increment()

console.log('after:', increment);
```

```js:modules/increment.js
import Caluculator from './modules/increment';

console.log('before:', 0);
console.log('***increment***');

const increment = new Caluculator(0).increment()

console.log('after:', increment);
```

これをwebpackコマンドで実行した結果が以下のようになります。
https://github.com/Shagamii/babel-introduction/blob/master/with-webpack/output/bundle.js
[babelを通してないもの](https://github.com/Shagamii/babel-introduction/blob/master/with-webpack/output/bundle_no_babel.js)と比べてみてください。
こちらからもes6の記法がes5に変換されているのがわかります。

実行結果はいづれも以下のようになります。

```shell:実行結果
before: 0
***increment***
after: 1
```

# まとめ
なんとなくbabelについてわかっていただけたでしょうか？
babelについて説明しましたが、早くbabelがいらない世界が来るといいですね！
より学習したい方は以下の参考リンクを読んでみてください！

# 参考リンク
[Babel](https://babeljs.io/)
[Babelの手ほどき](https://app.codegrid.net/entry/babel-1)
[Babel Cli の使い方](https://mae.chab.in/archives/2845)
[【５分でなんとなく理解！】Webpack入門](http://qiita.com/Shagamii/items/698a67bab0cd5eefcb4f)