このブログの構成を少しアップデートしようかと思っている今日この頃です。
さて、最近仕事でも実際にjsをゴリゴリ書くときはなるべく脱jQueryかつES6でコーディングするようにしており、ES6の形式にも少しずつ慣れてきて使いやすさは感じてきたところなのです。特にPromiseなんかはとても便利な機能でお世話になっていますが、ここでも問題になるのがフロンエンドエンジニアにとっての敵であるIEですね。IEはES6の書式に対応していないのでES6で書かれたjsではピクリともしてくれないわけです。
そこでES6のjavascriptのコードをES5に変換(トランスパイル)する必要があるのですが、今回は一番使われているBabelを使った変換方法を紹介したいと思います。ちなみに、環境はMacになります。
環境
まず、今回の環境ですが前回同様下記の環境を前提に進めていきたいと思います。
今回の環境
- Mac OSX Mojave 10.14.5
- Node.js v10.12.0
- NPM 6.11.3
- Babel 7.6.2
プロジェクト作成
まずは、簡単なプロジェクトを作成してみます。
$ mkdir es6-5
こんな感じで今回は「es6-5」というディレクトリを作成します。
ES6でコードを記述
続いて、簡単なコードをES6の書式にしたがって書いてみます。とりあえず「es6.js」というjavascriptファイルを作成して下記のような簡単なHelloWorldを書いてみます。
class HelloWorld {
constructor(args) {
this.message = args.message;
}
hello () {
console.log(this.message);
}
}
const hw = new HelloWorld({
message : 'Hello World!'
});
hw.hello();
これを実行するとコンソールに「Hello World!」と表示されると思います。
Babelをインストール
では、このES6の書式で書かれたjavasccriptファイルをES5に変換していきたいと思いますが、今回は冒頭でも述べた通り「Babel」を使って変換してみたいと思います。
初期化(package.jsonの作成)
まずは、下記のとおり先ほど生成したプロジェクトディレクトリに移動して、初期化(package.jsonを作成)をします。
$ cd es6-5
$ npm init
いろいろと聞かれますが、とりあえず全てEnterで大丈夫です。
完了すると、プロジェクトディレクトリ内に「package.json」ファイルが生成されていると思います。
なお、質問にいちいち答えるのが面倒な場合は下記のコマンドで省略することも可能です。
$ npm init -y
すべてYesと答えるということですね。
Babel-cliのインストール
続いて、Babel-cliを下記コマンドを実行してインストールします。
$ npm install --save-dev @babel/core @babel/cli
インストールが完了したらプロジェクトディレクトリに「node_modules」というディレクトリと「package-lock.json」というファイルが生成されたと思います。
また、さきほど生成された「package.json」も下記のような記述が追加されていると思います。Babel-cliのバージョン等が記載されてありますね。
"devDependencies": {
"@babel/cli": "^7.6.2",
"@babel/core": "^7.6.2"
}
念の為、問題ないかバージョンを表示するコマンドを叩いてみます。
$ ./node_modules/.bin/babel --version
7.6.2 (@babel/core 7.6.2)
上記のようにバージョン名が表示されていれば問題なくインストールされています。
ちなみに、Babel-cliはグローバル環境にインストールしてもいいのですが、公式でも推奨されているようにプロジェクトごとにインストールして利用するようにしましょう。これはプロジェクトごとに用途が異なるため推奨されていることになります。
.babelrcファイルの準備
続いて、ES6のコードをES5に変換するために「.babelrc」を作成するのですが、その前に「babel-preset-env」というプリセットをインストールします。
$ npm install --save-dev @babel/preset-env
インストールが完了したら、再度「package.json」ファイルを開いてみて下記のように記述が追加されていることを確認します。
"devDependencies": {
"@babel/cli": "^7.6.2",
"@babel/core": "^7.6.2",
"@babel/preset-env": "^7.6.2"
}
問題なくインストールできたら、続いて「.babelrc」ファイルを生成し、
$ vi .babelrc
下記のコードを記述して保存します。下記コードは@babel/preset-envのデフォルトの設定が適用され市場の0.25%以上のシェアを持つブラウザに対応したjavascriptのコードに変換してくれます。
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": 3
}
]
]
}
なお、下記のようにブラウザのバージョンを指定することも可能です。
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": 11
},
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
ES6をES5に変換してみる
これで下準備は完了なので、実際に下記コマンドでES6のコードをES5に変換してみます。
$ ./node_modules/.bin/babel es6.js
上記のコードを実行するとターミナル上に変換されたコードが表示されると思います。
変換してファイルに保存する
上記の方法だとターミナル上に変換されたコードが表示されるだけなので、下記コードで名前を付けて別ファイルに保存してみます。
$ ./node_modules/.bin/babel es6.js -o es5.js
これを実行すると「es5.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 HelloWorld =
/*#__PURE__*/
function () {
function HelloWorld(args) {
_classCallCheck(this, HelloWorld);
this.message = args.message;
}
_createClass(HelloWorld, [{
key: "hello",
value: function hello() {
console.log(this.message);
}
}]);
return HelloWorld;
}();
var hw = new HelloWorld({
message: 'Hello World!'
});
hw.hello();
変換されていることが確認できますね。このように変換したjavascriptファイルを利用すればIE11でも動作するようになります。
ついでにminifyもしてみる
基本的には上記の変換コードで問題なく動作すると思いますが、せっかくなのでminify化して軽量化までしてみます。
Babelを使ってminifi化するためには、まず下記コマンドで「babel-preset-minify」をインストールします。
$ npm install babel-preset-minify --save-dev
インストールしたら、下記コマンドを実行することでES5に変換しつつminify化したファイルを生成することができます。
$ ./node_modules/.bin/babel es6.js --presets minify -o es5.min.js
Promiseとかも使いたいよね
ということで、今回はこんな感じで終わりといきたいところですが、そこはさすがはIEさん。これではまだ不完全なんですね。
ES6ではPromiseをはじめ様々な機能が新たに含まれた(プラグインとしては古くから存在している)のですが、これらの機能を使おうとなるともう一手間対処してあげないといけません。
Promiseを使いたい場合、一番手っ取り早いのは、下記のPolyfillファイルをかましてあげる方法です。
先ほど変換したES5のファイルを読み込む前にこやつを読み込んであげることで、IE11でもPromiseが動作してくれるようになります。
Webpackでバンドルしてみる
上記の方法でもいいのですが、せっかくBabelを使っているので面倒ですが少し踏み込んでWebpackもインストールしてコンパイルする方法も試してみたいと思います。
まず、PromiseがIE11でも動くようにするために必要なものを下記コマンドを実行してインストールします。
$ npm install --save-dev core-js regenerator-runtime webpack webpack-cli babel-loader
インストールが完了したら、「package.json」ファイルを開いて「scripts」に「"build": "webpack"」という記述を追加してnpmでbuildするときにwebpackを使えるようにします。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
さらに、「webpack.config.js」を作成し、
$ vi webpack.config.js
下記のように記述して、ES6からES5に変換された「es5.js」を「bundle.js」というファイルにコンパイルするようにします。
const path = require('path');
module.exports = {
mode: "development",
entry: path.resolve(__dirname, "es5.js"),
output: {
path: path.resolve(__dirname),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: "babel-loader",
}
]
}
]
}
};
続いて、「.babelrc」ファイルの「useBuiltIns」が「entry」になっている場合は、「usage」に変更しておきます。
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
ここまできたら、改めて下記コマンドでES6をES5に変換します。
$ ./node_modules/.bin/babel es6.js -o es5.js
そうすると更新された「es5.js」ファイルに新たにいくつかのrequire文が挿入されたと思います。これらのファイルがIE11等でPromiseを動作させるために必要なモジュールになります。
require("core-js/modules/es.object.define-property");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
require("core-js/modules/web.timers");
そして、最後に下記コマンドでこの出来上がった「es5.js」をwebpackでビルドしてあげてコンパイルします。
$ npm run build
そうすると「bundle.js」というファイルが生成されるので、このファイルを実際に使用することでIE11でもPromise(他のIE11非対応の機能も可)を動作させることができます。
まとめ
ということで、今回はES6の書式で書かれたjavascriptファイルをIE11でも動作するようにBabelを使ってES5に変換する方法や、Promise等のIE11で利用できない機能を使えるようにする方法を紹介させていただきました。
まだIE11には対応しないといけないことが多いと思いますが、IE11のためにこんな面倒なことをしないといけないので早いとこIEのシェアが0になってくれるとありがたいですね(笑)。
てことで、今回はここまで!また!