5分でなんとなく理解するシリーズ、前回のWebpack入門に続き、第2回はBabel入門です!
はじめに
この記事は、理科大AdventCalendar23日目の予定だったものです!
このAdvent Calendarの作成者にも関わらず、間に合わなくてすみません!
僕は、この理科大AdventCalendarで先に投稿していただいたkatsuyukiさんとgangunさんがおっしゃっていた今はなきi科のあと誕生したI科こと情報工学科の一期生で2年生です!
理科大生を中心とした学生団体Unitusで活動したり、ベンチャーでインターンをさせていただいたり、Nihonbashi.jsという勉強会を第2回から企画・運営をさせていただいてます。
AdventCalendarということで自分しか書けない記事を書きたいと思っていたのですが、4ヶ月以上7割完成のまま放置されていた記事があったのでとりあえず供養しようと思います。
Babelとは
Babelとは、簡潔にいうと、JavaScriptのコードを新しい書き方から古い書き方へと変換するツールです。
なんでコードを変換しないといけないの?
JavaScriptはEcmaScriptで定められた仕様にしたがって実装されています。
現在、es6と呼ばれる6番目のバージョンまで策定が完了しており、es7が策定中となっています。
そのため、現在エンジニアによって書かれているコードは主にes6がメインとなっているのですが、各ブラウザで実装されていないes6の仕様が多くあります。
また、Node.jsで実行する際もバージョンによって実行できる仕様が異なります。
そのため、ブラウザで使用するまたは、実行環境として考えられるNode.jsのバージョンが定まっていない場合、それぞれの環境で実行するためにそれぞれの環境に合わせてes5の記法に変換する必要があります。
いろいろなビルドツールとの組み合わせ
babelは単体で使用されることもありますが、様々な種類のビルドツールとの組み合わせで使われることが多いです。
ビルドツールとは、様々な環境に合わせて、モジュールの依存解決、ファイルのトランスパイル、圧縮などを行いやすくするツールと考えてもらえればいいと思います。
ビルドツールでファイルをまとめる時に、babelで変換もする、そんな感じです。
ビルドツールの中でも、前回紹介したWebpackや、さらに機能が広範囲に及ぶbrowserify、gulpなど種類はさまざまです。
最近では、parcelと呼ばれるツールも誕生しました。筆者も軽く使ってみましたが、ほとんど設定ファイルも書かずに手軽に実行できるので便利です。
また、使用用途によって技術選定をするわけですが、今回のサンプルでは、個人的に使い慣れていて、parcel出てきても開発ではまだまだ使いそうという理由で、Webpackを用いています。
ビルドツールについてより詳しく知りたい方
様々な機能
様々なplugin
pluginで設定することで、es6で定められたそれぞれの仕様に対して、それぞれ変換することができます。
様々なpresets
babelでは、様々presetsを導入することができ、例えば、変換すると同時にflowのために書いた型を取り除いてくれる「flow」や、
できる限り最新のes関連のpresetsまでを含むもしくは、指定したNode.js、ブラウザのバージョンまで必要なpluginをインストールする「env」などがあります。
主なplugin、presets
実行手順
babelのみの場合
- node.jsの実行環境を整える
- babel-cliをインストール
- plugin、presetsをインストール
- .babelrcに設定を書く
babel+Webpackで動かす場合
- node.jsの実行環境を整える
- babel-loader,babel-coreをインストール
- plugin、presetsをインストール
- Webpackのmoduleにbabelの設定を書く
- .babelrcに設定を書く
.babelrcを書かずにbabelの実行時にコマンドオプションとして使う方法や、webpackに直接書く方法もあります。
実際に動かすコマンドに関しては以下のリンクをなどを参考にしてみてください。
babelの実行手順についてもっと知る
どんなふうにうごくの?
それではサンプルコードを用いて動きを確認してみましょう。
bebelのみの場合
ディレクトリ構造は以下のようになっています。
.
├── .babelrc
├── output
│ └── index.js
├── package.json
└── src
└── index.js
babelrcは以下のようになリます。今回はpresetsでenvを使用しました。
{
"presets": ["env"]
}
サンプルコードを動かす
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);
babel src -d output
以下がbabelを通した後になります。
'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の設定ファイルは以下のようになります。
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",
}
]
}
};
サンプルコードを動かす
import Caluculator from './modules/increment';
console.log('before:', 0);
console.log('***increment***');
const increment = new Caluculator(0).increment()
console.log('after:', increment);
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を通してないものと比べてみてください。
こちらからもes6の記法がes5に変換されているのがわかります。
実行結果はいづれも以下のようになります。
before: 0
***increment***
after: 1
まとめ
なんとなくbabelについてわかっていただけたでしょうか?
babelについて説明しましたが、早くbabelがいらない世界が来るといいですね!
より学習したい方は以下の参考リンクを読んでみてください!