Gruntfile.js が長すぎてつらい人は gulp を使ってみよう


`Gruntfile.js` は常々長すぎると思っていました。複数ファイルに分割しようが長いものは長いです。

最近、後発の [gulp](http://gulpjs.com/) というものを見つけて使ってみていますが、いい感じです。 **設定ファイルが短く書ける上に、速いです。**

先日 [Grunt 入門の記事「Web デザイナーさん向け Grunt を使った コーディング作業の効率化、はじめの一歩」](http://hyper-text.org/archives/2014/01/grunt_quick_start_for_web_designer.shtml)を読んで、例の Gruntfile.js と同等の内容を gulp で書いたらどうなるかなと思って書いてみました。

- [サンプルファイル含めたプロジェクト全体](https://github.com/shuhei/gulp-quick-start)
- [gulpfile.js だけ](https://github.com/shuhei/gulp-quick-start/blob/master/gulpfile.js)

67 行から 29 行に。約半減です。また、短くなっただけではなく、処理の流れがわかりやすくなっていると思います。

```gulpfile.js
var gulp = require('gulp');
var concat = require('gulp-concat');
var prefixer = require('gulp-autoprefixer');
var minify = require('gulp-minify-css');
var imagemin = require('gulp-imagemin');
var plumber = require('gulp-plumber');
 
gulp.task('css', function () {
  gulp.src('htdocs/css/**/*.css')
      .pipe(plumber())
      .pipe(prefixer('last 2 version'))
      .pipe(concat('style.min.css'))
      .pipe(minify())
      .pipe(gulp.dest('htdocs/dist/css'));
});
 
gulp.task('img', function () {
  gulp.src('htdocs/img/**/*')
      .pipe(plumber())
      .pipe(imagemin())
      .pipe(gulp.dest('htdocs/dist/img'));
});
 
gulp.task('watch', function () {
  gulp.watch('htdocs/css/**/*', ['css']);
  gulp.watch('htdocs/img/**/*', ['img']);
});
 
gulp.task('default', ['css', 'img']);
```

## そもそも gulp って？

gulp は [Node.js の stream](http://nodejs.org/api/stream.html) を使って Grunt の行っているようなことをもっとうまくやろうというものです。以下のような特徴があります。

- **設定ファイルの可読性**: 例えば CSS に対して何の処理をするのか一目瞭然です。
- **スピード**: タスクはできる限り並列に実行されるので速いです。中間ファイルも生成されません。
- **拡張性**: プラグインが対応していないことをやりたければ、自分で少しプログラムを書くだけすみます。

## そもそも stream って？

ざっくり言うと、データの流れを抽象化するためのインターフェイスだそうです。

ここでは詳しく説明しませんが gulp の開発者達は [substack's stream handbook](https://github.com/substack/stream-handbook) を読めと言っています。

## gulp の stream は？

通常 gulp のタスクは、ざっくり言うと以下のような流れです。

1. `gulp.src()` でファイルの stream を作ります。
2. 各プラグインが stream の中を流れるファイルを処理して、また stream に流します。
3. `gulp.dest()` で stream の中を流れてきたファイルを保存します。

ここで注意すべきは、gulp の扱う stream の中を流れるのは、ファイル一個に対応するオブジェクトだということです。具体的には [vinyl という npm パッケージ](https://github.com/wearefractal/vinyl) で決まっている `File` オブジェクトです。ざっくり言うと、ファイルのパスとファイルの中身の情報を持っています。

例えば `htdocs/css/**/*.css` にマッチする CSS ファイルが 3 つあったとすると、`gulp.src('htdocs/css/**/*.css')` は `File` オブジェクトを 3 つ流す stream を返します。

こうやってファイルに対応する object を stream に流すことで、複数のファイルをどんどん処理できるわけですね。

ちなみに 2. のところを厳密に言うと、各プラグインは、入ってくる File オブジェクトを変換して出す stream を作ります。いわゆる [Transform Stream](http://nodejs.org/api/stream.html#stream_class_stream_transform) ですね。

## プラグインは充実してるの？

あまりいろいろ試していないのですが、思いつくようなものはだいたいあるんじゃないでしょうか。

- [オフィシャルサイトのプラグインページ](http://gratimax.github.io/search-gulp-plugins/)
- あとは普通に [npm](https://npmjs.org/) で "gulp hoge" と検索

基本的には、もともとある npm パッケージをラップするだけなので、なければ誰かがすぐ作ってしまいます。

いざとなれば [Grunt タスクを gulp から使うためのプラグイン](https://github.com/gratimax/gulp-grunt) もあるようです。

## 使ってみよう

例を見ればすぐわかるシンプルさなので、ぜひためしに使ってみてください。

1. まだなら Node.js をインストール。
2. `npm install -g gulp`
3. プロジェクトに `package.json` がなければ `npm init`
4. `npm install -save-dev gulp gulp-hoge` で gulp と必要なプラグインを入れる。
5. `gulpfile.js` を書く。
6. `gulp`

ほしい機能のプラグインも、"gulp hoge" とかで検索すれば大抵すぐ出てきます。

## 参考資料

- [公式サイト](http://gulpjs.com/)
- [GitHub](https://github.com/gulpjs/gulp)
- [作者による紹介スライド](http://slid.es/contra/gulp)
- [Stream Handbook](https://github.com/substack/stream-handbook)