2016/08/19更新

[フロントエンド] ES2015のimport/exportをブラウザで使うためのコンパイル(Babel × Browserify)

このエントリーをはてなブックマークに追加      

こんにちは、フロントエンドのリハビリ中@yoheiMuneです。
今日はES2015(ES6)から言語レベルでサポートされたモジュール定義について、ブラウザで利用するための方法をブログに書きたいと思います。

画像

目次




ES6のimport/exportはまだブラウザで使えない

ES6から利用可能なimportexportによるモジュール定義と利用ですが、残念ながらまだブラウザでは使うことができません。例えば以下のようなコードがあった場合に、
import React from "react"
Chromeだと以下のようなエラーが発生します。
# Chrome v53の場合
Uncaught SyntaxError: Unexpected token import
そして前回、「[フロントエンド] 次世代JavaScriptのコンパイラ、Babelに入門」でES6をES5にコンパイルする方法を紹介しましたが、残念ながらimportexportは使える状態にはコンパイルされません。例えば以下のコードがある場合に、
// hello.js
export function hello () {
    console.log("Hello from a.js");
};
// my-file.js
import {hello} from './hello.js';
hello();
Babelでコンパイルすると以下のようになります。
# Babelでコンパイル
$ babel -o hello-comiled.js hello.js
$ babel -o my-file-comiled.js my-file.js
// hello-compiled.js
"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.hello = hello;
function hello() {
    console.log("Hello from a.js");
};
// my-file-compiled.js
'use strict';
var _hello = require('./hello.js');
(0, _hello.hello)();
上記のようにexportsrequireを用いた方式(Nodeの方式)にコンパイルされてしまいます。
この状態でブラウザで使おうとすると以下のようにエラーとなってしまいます。
# Chrome v53の場合
Uncaught ReferenceError: require is not defined
ということで、EcmaScript6のインポートとエクスポートを使う場合には追加のコンパイルが必要となります。



Browserify × Babelを用いてコンパイルする

ES6のimportexportをブラウザで使えるようにする方法は幾つかありますが、ここでは手軽なBrowserifyを用いた方法を紹介します。Browserify自体の紹介は以下でブログを書きましたので参照いただけますと幸いです。

[フロントエンド] nodeモジュール管理がフロントで使えるBrowserifyに入門

[フロントエンド] gulpからBrowserifyを利用する、watchでコンパイルする

具体的にはBrowserifyのトランスフォーム(transform)という機能で、Babelifyを用いて変換を行います。まずはBabelifyをインストールします。
# Babelifyの導入
$ npm install --save-dev babelify
そして以下のようにBrowserifyを実行します。
# Babelifyを用いたコンパイル
$ browserify --transform babelify --outfile my-file-compiled2.js my-file.js
すると以下のように変換され、ブラウザから利用することができるようになります。
// my-file-compiled2.js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.hello = hello;
function hello() {
    console.log("Hello from a.js");
};

},{}],2:[function(require,module,exports){
'use strict';

var _hello = require('./hello.js');

(0, _hello.hello)();

},{"./hello.js":1}]},{},[2]);
また、gulpで以下のように実装することでgulp経由でコンパイルすることもできます。
// gulpfile.js
"use strict";
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');

gulp.task('browserify', function () {
    browserify({
        entries: './my-file.js'
    })
    .transform(babelify)
    .bundle()
    .pipe(source("myfile.js"))
    .pipe(gulp.dest("./dest"));
});
# gulp実行
$ gulp browserify
transformを指定する以外は普通のビルドですね!



エラーが発生したら

僕がやった時には最初以下のようなエラーが発生しました。
'import' and 'export' may appear only with 'sourceType: module'
どうもよくよく調べたところ、Babelのpresetes2015を指定し忘れたのが原因のようでした。npmで以下のようにモジュールをインストールして、
$ npm install --save-dev babel-preset-es2015
また、以下の.babelrcを準備することで無事に動きました。
// .babelrc
{
    "presets": [
        "es2015"
    ]
}
隠れた設定ファイルが必要なあたり、Babelのはまりどころの1つですね。



参考記事

今回の内容を実装するために以下の記事を参照しました。ありがとうございます。

babelifyで始めるES6 - to-R



最後に

ES2015スタイルでコードを書けるってなかなか素敵ですね。良い仕様は早めに取り込んで実装の品質アップを図りたいものです。

最後になりますが本ブログでは、フロントエンド・開発関連・Swift・Linux・Python・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSTwitterをフォローして頂けると幸いです ^ ^。

最後までご覧頂きましてありがとうございました!





こんな記事もいかがですか?

[取り組み] フロントエンドでコーディングスピードをアップさせる6つの方法!と思って書いてたら30個も書いちゃった。
[フロントエンド] フロントエンドの入社試験99問!難しいですよ〜w。
[フロントエンド] Webページを表示するテストの際に、通信速度を3Gに制限して表示してみよう
[フロントエンド] スマホ実機でのデバッグ手段を増やす!Macのプロキシを利用して、通信内容を確認する。
[フロントエンド] Chrome 35 Beta の変更点。Touch制御、新しいJavaScript機能、プレフィックスなしのShadowDOM
[フロントエンド]複数アカウントでのテストには、Chromeのユーザー管理を使って、Cookieを切り替えると便利
[フロントエンド] Chrome36βが出た。変更点など。element.animate、HTML Imports、Object.observe、他。
RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。