アレがアレでアレ

(できれば)プログラミング関係のことを書きたい

Babelを使ってみる

babeljs.io

Babel、どんなツールか知っていたけれど使ったことなかったので試してみます。
webpack + Babelで使うのをよく見ますが、とりあえずBabelだけコマンドラインから使ってみます。

Babelとはなにか

簡単に言うと、新しいJavaScriptの書き方で書いたコードを古い書き方のコードへ変換するツールです。
なぜせっかく新しい構文で書いたのにわざわざ古い方へ変換しなきゃいけないかというと、 ブラウザごとにJavaScriptの新バージョンへの対応状況が違うので、新しい書き方だと動いてくれないブラウザがあるからです。(※IEとかIEとかIEとかね)

ということで、Babelを使って変換すればブラウザが対応してない構文でも気にせずコーディングできます。

Babelの環境構築

実行環境

  • Node.js: 11.10.1
  • npm: 6.7.0

npmで必要なパッケージをインストールします。
インストールする前にnpm init -ypackage.jsonを作っておきます。

$ npm install --save-dev @babel/core @babel/cli @babel/preset-env

設定ファイル

babel.config.jsというファイルを作って、ここにBabelの設定を書いていきます。

const presets =  [
  ['@babel/preset-env', {
    'targets': {
      'ie': '11',
      'chrome': '58'
    }
  }]
];
module.exports = { presets }

使用するプリセット(@babel/preset-env)と、targetsにサポートするブラウザのバージョンを指定します。 指定した環境を最低限サポートするよう変換してくれます。

babeljs.io

Babel実行

試しに以下のJavaScriptを変換してみます。
どれもIE11では対応していないECMAScript2015の構文で書いてみました。

index.js

const add = (a, b) => a + b;

class Person {
  constructor(age, name) {
    this.age = age;
    this.name = name;
  }
  toString() {
    return `name=${this.name}, age=${this.age}`;
  }
}

const numbers = [1, 2, 3, 4, 5];
for (const number of numbers.map(x => x * 2)) {
  console.log(number);
}

次にpackage.jsonにBabelの実行コマンドを登録しておきましょう。
ここでは、srcというフォルダに先程のindex.jsを用意して変換してみます。
-oオプションで変換後のファイルを出力できます。distフォルダに出力することにします。

"scripts": {
  "build": "./node_modules/.bin/babel src/index.js -o dist/index.js"
},

保存したらpackage.jsonがある場所で

$ npm run build

変換後のindex.js

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var add = function add(a, b) {
  return a + b;
};

var Person =
/*#__PURE__*/
function () {
  function Person(age, name) {
    _classCallCheck(this, Person);

    this.age = age;
    this.name = name;
  }

  _createClass(Person, [{
    key: "toString",
    value: function toString() {
      return "name=".concat(this.name, ", age=").concat(this.age);
    }
  }]);

  return Person;
}();

var numbers = [1, 2, 3, 4, 5];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;

try {
  for (var _iterator = numbers.map(function (x) {
    return x * 2;
  })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
    var number = _step.value;
    console.log(number);
  }
} catch (err) {
  _didIteratorError = true;
  _iteratorError = err;
} finally {
  try {
    if (!_iteratorNormalCompletion && _iterator.return != null) {
      _iterator.return();
    }
  } finally {
    if (_didIteratorError) {
      throw _iteratorError;
    }
  }
}

はい。ちゃんとアロー関数やクラス、for ofループが変換されています。
for ofループのとこなんかぱっと見た感じ何やってんのか分からないレベルですね...

他にもいろいろ設定があったりするのですが、とりあえずES2015の構文が変換できればいいということで終わりにします。