webpack + babel-loaderでES6デビューしつつ、gulpもES6で書く

  • 111
    いいね
  • 0
    コメント

こんにちは!ギャザリーで開発を担当している手塚@inureoです。
今回はタイトル通りwebpack + babel-loaderでES6デビューしつつ、gulpもES6で書く、というところをやってみたいと思います。

gulpfile.jsをES6で書こうと思った理由

「ES6やりたいなー、しかも業務に直結するところで。」と考えていた時に、こちらの記事のgulpfile.js
をES6で書く理由を拝見して「たしかにgulpfileなら実装に頭使わないし慣れるのにはピッタリだ!」と思ったからです。

早速ES6でgulpfileを書いていく

gulpfileをES6で書くには、gulp側でES6対応をするか、node.js側でES6対応をするかの2択になります。

gulp側での対応

gulpの3.9.0からbabelを標準サポートするようになりました。ファイル名をgulpfile.babel.jsに変更すればbabelを介してES6の構文を利用することができます。

node.js側での対応

node.jsはv4.0.0からES6に一部対応をしました。なので、node.jsのバージョンが4.0.0以上であればES6の構文をそのまま利用することができます。
こちらは gulpfile.js のままで問題ありません。

参考:gulpfile.jsをES6で書いてみよう - tacamy.blog

今回の対応

自身の環境がv0.12.7だったので、gulp側で対応をすることにしました。

ES6構文を使ってみる

早速次のように import を使ったり、 arrow function を使ったりしてみます。

'use strict';

import gulp from 'gulp';
import runSequence from 'run-sequence';

gulp.task('build', () => {
  runSequence(
    ...
  );
});

こちらで実行すると、 import でコケてしまいます。

[21:53:35] Requiring external module babel-core/register
/Users/tezukaryo/src/es6-gulp-boilerplate/gulpfile.babel.js:3
import gulp from 'gulp';
^^^^^^

import を使うには次のpresetが必要なようなので、インストールをして.babelrcに追記します。

$ npm install --save-dev babel-preset-es2015
{
  "presets": ["es2015"]
}

追記した上で実行すると正しく動作するかと思います。

gulpfileをES6で書いていく上でハマったところはそれぐらいですね。あとは、いつもどおりタスクを記述していけば問題ありません。冒頭で言っていましたが、頭をあまり使わないですむのでES6に慣れるにはとてもよいなーと思いました。

参考:gulpfileをES6で書く - Qiita

webpack + babel-loaderを使ってES6をビルドする

さて次は webpack + babel-loader でES6をビルドできるようにしてきます。まずは設定ファイルであるwebpack.config.jsをルートディレクトリに作ります。

このwebpack.config.jsの設定が長くなるので、gulpfile側では次のような形でタスクを作り、設定ファイルを読み込ませておきます。

gulpfile.babel.js
import webpackConfig from './webpack.config.js';

gulp.task('webpack', () => {
  gulp.src('source/assets/javascripts/**/*.js')
    .pipe($.webpack(webpackConfig))
    .pipe(gulp.dest('dist/assets/javascripts/'));
});

webpackのオプションの説明

webpackはオプションが豊富です。今回はよく使うであろう(今回使った)ものを簡単に説明していきます。

entry

実際に依存関係を解決して出力するファイルになります。オブジェクト形式でキーの部分に名前を入力することで、ファイル名を変えずに指定した名前で出力することができます。

  entry: {
    animal: ['./source/assets/javascripts/animal.js'],
    dog: './source/assets/javascripts/dog.js',
    vendor: ['jquery']
  },

animal.jsは[]でくくられていますが、dog.jsはくくられていませんね。こちらハマりポイントです。animal.jsはdog.jsでimportをされているので、[]でくくっています。くくらずにビルドした場合、次のようなエラーが出ます。

ERROR in ./source/assets/javascripts/dog.js
Module not found: Error: a dependency to an entry point is not allowed
 @ ./source/assets/javascripts/dog.js 1:578-597

[]でくくる理由については下記参考URLをご覧ください。

参考:Error: a dependency to an entry point is not allowed · Issue #300 · webpack/webpack

output

出力先やファイル名を設定することができます。filenameに[name]とすることで、entryで指定したキー名でファイルが出力されます。

  output: {
    path: __dirname + '/dist/assets/javascripts/',
    filename: '[name].js'
  },

resolve

読み込む際に拡張子を省略できるようにするんだとか。

resolve: {
    extenstions: ['', '.js', '.json', '.html']
}

module

webpackの大きな特徴である loader の設定をするところです。webpackはjs以外のどんなファイルでも、loaderさえ使えば読み込むことができます。

今回は次のようにbabel-loaderを設定しました。.jsという拡張子のファイルかつnode_modulesディレクトリは対象外と設定していあす。

  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  },

plugins

こちらもloaderと同じぐらい特徴的な機能です。ドキュメントが大量にあるので詳しくはそちらをご覧ください。今回使ったものだけ簡単に紹介しますね。

AggressiveMergingPlugin

ファイルを細かく分析してまとめられるところは可能な限りまとめて圧縮するオプション

DedupePlugin

被っているモジュールがあったら1つにまとめるオプション

CommonsChunkPlugin

npmとかでインストールしたライブラリをまとめたりするもの…?あまりよくわかっていないですが、皆さんそんな使い方をされていたので、僕もjQueryを固めています。(どなたか教えてください!)

  plugins: [
    new webpack.optimize.AggressiveMergingPlugin(),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      filename: 'vendor.js',
      minChunks: Infinity
    })
  ]

参考:webpackを使い倒す - Thujikun blog

ES6ファイルをビルドする

さて説明した内容そのままで設定ファイルを完成させれば、babel-loaderを使ってES6構文を使ったファイルが依存関係を解消した状態でビルドできるはずです。

実際の設定ファイルを参考に、自身の環境に調整して試してみてください。紹介したものはほんの一部なので、様々なオプションを触って使いこなしていきたいですね。

というところで、導入編はおしまいです。

各gulpタスクで使用する技術の選定

次に今回のgulpfileで使用した技術の選定理由などを説明したいと思います。

webpack

modular には、browserifyではなくwebpackを使うことにしました。理由としては、個人的にwebpackの 最適なアセットの生成を目的にしている というところに感銘を受けたためです。

webpackは日本語の情報が少なかったりしますが、最近は日本語のリファレンスも増えてきてそこまで死にそうになることは少ないかなと思います(今回webpack化に挑戦する前に一度諦めてたりしてます)。
また、ビルドの速度がbrowserifyと比べて早いというのも選択理由の1つです。

一回(もしくはwatchの初回)のビルド時間
Browserify => 3〜4分
Webpack => 14〜16秒(!)

JavaScript - BrowserifyからWebpackへの移行時の注意点 - Qiita

ESLint

業務でもお世話になっているAirbnbがESLintのconfigファイルを配布していたので、こちらをそのまま使いました。

javascript/packages/eslint-config-airbnb at master · airbnb/javascript

npm

Bowerは個人的に使いたくなかったので(package.jsonとbower.jsonの2重管理がいやだった)今回はnpmでjQueryをインストールしています。Bowerにしかないものもあったりすると思うのですが、それは困ったときにでもという感じです!webpackであれば問題なくBowerで管理されているものを扱えるので。。

node-sass

Compassを捨てて、autoprefixerを使うようにしました。Compassはとても便利なのですが十分に使いこなせなかったりで、オーバースペック気味になることが多かったです。
であれば速度重視でnode-sassに移行した方が結果的に生産性が上がるだろうなーと思い、今回のタイミングで完全に移行してみました。
個人的なプロジェクトでStylusも触ってみたのですが、Sassをずっと使ってたいたせいか、ゆるゆるな感じ(変数がなくても怒られないとか)が落ち着かなくてSassに帰ってきました。

最終的にできたもの

さてさていろんな理由を経て最終的にできたものは、node.js >=0.12 で動作するスターターキット的なものです。ちょっと見通しが悪いので今後アップデートしていく予定です!

inureo/es6-gulp-boilerplate

できること

  • JadeやらSassやらES6のコンパイル
  • AirbnbのスタイルガイドにそったESlint
  • 画像サイズの最適化とスプライト画像生成
  • browserSyncを使ったローカルサーバの起動、ブラウザの自動更新

今後のアップデート予定

  • タスクをファイルごとに分割して見通しをよくする
    • 2016/05/28 分割対応した
  • Enviromentでminifyをするかどうかわける
    • 2016/05/28 webpackタスクに適応した

感想

ES6に慣れるにはgulpfileで試すのは結構よいかもしれませんね。個人的にはwebpackのオプションの多さに驚かされたので、早速業務で色々試してみようと思います。

お世話になった記事

参考にさせていただきました!ありがとうございます!