gulp-babelでES6(ES2015)をES5に変換してNode.jsでもブラウザでも使えるようにUMD化する
JSプラグインを作る際、BabelでES6を使いつつ、Node.jsでもブラウザでもどちらの環境でも使えるようにする方法の紹介です。
ES6→ES5に変換
npm i gulp gulp-babel babel-core babel-preset-env -D
まずは、必要となるライブラリをインストールします。gulp-babel はgulpでbabelを使えるようにするもので、 gulp-core はbabelの実行に必要なもの、 babel-preset-env はES5に変換する際のプリセットです。
class Foo {
bar() {
alert('bar');
}
}
コンパイルするサンプルプログラムとして script.es6 ファイルを作成し、このように書いておきます。
const gulp = require('gulp');
const babel = require('gulp-babel');
gulp.task('compile', function() {
gulp
.src('script.es6')
.pipe(babel({
presets: ['env']
}))
.pipe(gulp.dest('./'));
});
gulpfile.js を作成します。
gulp compile
あとは、 gulp
コマンドでコンパイルします。
'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 Foo = function () {
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [{
key: 'bar',
value: function bar() {
alert('bar');
}
}]);
return Foo;
}();
コンパイルできたら同じディレクトリにこのような script.js ができているはずです。
const gulp = require('gulp');
const babel = require('gulp-babel');
gulp.task('compile', function() {
gulp
.src('script.es6')
.pipe(babel({
presets: [
['env', {
'targets': {
'browsers': ['last 2 versions', 'safari >= 7']
}
}]
]
}))
.pipe(gulp.dest('./'));
});
また、 targets
にサポートするブラウザを指定すればその環境に合わせてコンパイルしてくれます。
他にもドキュメントを読むと色々 オプション があります。
UMD化
Node.jsでは import
や require
で、ブラウザからは script
要素から利用したい場合、両方に対応する必要があります。そこで、よく使われているのが UMD(Universal Module Definition) です。
(function (root, factory) {
// AMDのとき
if (typeof define === 'function' && define.amd) {
define([], factory);
}
// CommonJS(Node.js)のとき
else if (typeof exports === 'object') {
module.exports = factory();
}
// ブラウザのとき
else {
root.Lib = factory();
}
})(this, function () {
class Foo {
bar() {
alert('bar');
}
}
return Foo;
});
色々書き方はありますが、 UMD化 するとこんな感じで書くことができます。これを先ほどと同じくコンパイルしてみます。
'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; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
(function (root, factory) {
// AMDのとき
if (typeof define === 'function' && define.amd) {
define([], factory);
}
// CommonJS(Node.js)のとき
else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
module.exports = factory();
}
// ブラウザのとき
else {
root.Lib = factory();
}
})(undefined, function () {
var Foo = function () {
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [{
key: 'bar',
value: function bar() {
alert('bar');
}
}]);
return Foo;
}();
return Foo;
});
コンパイルはできましたが、このプログラムは正しく動作しません。コンパイル前とコンパイル後で見てみると、 this
が undefined
になってしまっています。
const gulp = require('gulp');
const babel = require('gulp-babel');
gulp.task('compile', function() {
gulp
.src('script.es6')
.pipe(babel({
presets: [
['env', { 'modules': false }]
]
}))
.pipe(gulp.dest('./'));
});
これを防ぐには gulpfile.js を少し修正します。'modules': false
を加えるとモジュールとして認識されなくなり正しくコンパイルできるようになります。
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; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
(function (root, factory) {
// AMDのとき
if (typeof define === 'function' && define.amd) {
define([], factory);
}
// CommonJS(Node.js)のとき
else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
module.exports = factory();
}
// ブラウザのとき
else {
root.Lib = factory();
}
})(this, function () {
var Foo = function () {
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [{
key: 'bar',
value: function bar() {
alert('bar');
}
}]);
return Foo;
}();
return Foo;
});
コンパイルしてみると、 this
のままであることが確認できます。
CSS本執筆しました!!!
CSS本出します!1/29発売予定
— たかもそ@CSS本1/29発売!! (@takamosoo) 2018年12月31日
自分がCSS学びたての頃にもっとはやく知りたかったテクニックを載せています。CSSの基礎知識について解説していないので、中級者〜向けとなります。CSS入門書を読んではみたものの、思い通りに作れない人にオススメです。
よろしくお願いします。https://t.co/fkz1dM03Pj pic.twitter.com/suYyaPqwIs