この記事のターゲット
- スプレッド構文が含まれたJavaScriptファイルを用意されたがEdgeに対応する必要がでてきた
- babelって聞いたことあるけど使ったことない
何やるか
babelについて簡単に説明し、どうして使うのか、何が嬉しいのかを理解した上で最低限の変換をかけるところまで行きます.
Babelってなに
公式 : Babel
Babelの前にJavaScriptについてちょっとだけ確認します。
一口にJavaScriptと言ってもその中には他のプログラミング言語と同様に様々なバージョンが存在します。
そんな中でも特にECMAScript 2015(ES2015(別名ES6))かそれ以前かでは大きな差分があり、とある環境では動いたものが別の環境では動かないということがままあります。
こんな時、バックエンド側のプログラミング言語であればチームで特定のバージョンに固定することで、開発環境では動いたのに本番環境では動かないというような事態を避けるのが一般的かとおもいます。
しかしながらJavaScriptの世界ではその解決策はあまり有効ではありません。
JavaScriptにとって実際に本番環境となるのはエンドユーザーが利用しているブラウザになるため、サービス提供側が固定できる要素ではないためです。
このようなことから業務系のサービスなどではサポートするブラウザをIEのみにするなどといった方法で対応することもあります。
とはいえ、toCサービスなどではブラウザの違いを気にしなければいけないなんて機会損失もいいところです。
可能なことならなるべく多くの環境で動くバージョンのJavaScriptで実装したいと考えるのは自然でしょう。
しかしJavaScirptのバージョンを高く保つのは開発者によりよい開発体験を提供するためにも必要不可欠です。
そんな時にこのBabelが役に立ちます。
Babelは新しいバージョンで書かれたJavaScriptを比較的古いバージョンのJavaScriptに書き直すトランスパイラです。
具体的な例をあげると、ES6で導入されたスプレッド構文などはEdgeなど一部ブラウザでは機能しません。
そのため、スプレッド構文で書かれたJavaScriptをBabelにかけることでEdgeでも解釈可能な構文で書き直してもらうわけです。
これで晴れて開発者には新しいバージョンでの開発体験を、エンドユーザーにはブラウザの違いを意識しないサービス提供が可能になる、ということです。
やってみよう
前置きが長くなりましたが本題に入りましょう。
package.jsonにbabel関連のものをかいてinstallします。
今回は特にスプレッド構文を書き直すために「@babel/plugin-proposal-object-rest-spread」というものを追加しています。
そう、実はデフォルトのbabelだけでは全ての構文を過去バージョンに書き換えることはできません。
そのためにpluginやpresetという形でたくさんの構文解析ルールが提供されています。
自分のプロジェクトに必要な物を適宜追加していきましょう。
"devDependencies": {
"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"babel-plugin-add-module-exports": "^1.0.2",
"babel-core": "^7.0.0-bridge.0",
}
yarn or npm i
続いて、babelに特殊なpluginを使うことを指定して教えてあげます。
babelに関する設定は.babelrcというファイルに書きます。
プロジェクトに存在しない場合は新規作成してください。
{
"plugins": [
"@babel/plugin-proposal-object-rest-spread",
],
}
これで準備完了です。
実際にトランスパイルしてみましょう。
まずはトランスパイルする前のファイルを用意。
mozilla公式のリファレンスからコードをちょっと拝借。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
var mergedObj = { ...obj1, ...obj2 };
console.log(clonedObj)
console.log(mergedObj)
コマンドラインでbabelを実行し、引数にこのファイルを渡します。
npx babel before.js
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var obj1 = {
foo: 'bar',
x: 42
};
var obj2 = {
foo: 'baz',
y: 13
};
var clonedObj = _objectSpread({}, obj1);
var mergedObj = _objectSpread({}, obj1, {}, obj2);
console.log(clonedObj);
console.log(mergedObj);
こんな出力がでたら成功です。
まとめ
自分だけが書いているコードならまだ気をつけようもありますが、OSSなどで取得してきたコードがES6以降だとEdgeはほぼ非対応になってしまいがちですね。
実際にサーバーに配置する際にminifyをかけることがあればその時に一緒にbabelを通すことで実行可能ブウラザが随分大きくなると思います。
マサカリ歓迎!