Gruntの代替ビルドツール。gulpをはじめる。

Gruntの代替のビルドツールの候補になっている[gulp](http://gulpjs.com/)。
その使い方と、タスクの書き方。

# インストール

## globalにinstall

```bash
$ npm install -g gulp
```

## localにもinstall

```bash
$ npm install gulp --save-dev
```

## gulpfile.jsを置く

``js:`gulpfile.js
var gulp = require('gulp’);
gulp.task('default', function() {
  // place code for your default task here
});
```

## 実行する

```bash
$ gulp
```

# プラグインの導入

`src/`以下の coffeeスクリプトをJavaScriptにコンパイルして`dist/`に移す場合

```bash
$ npm install gulp-coffee --save-dev
```

```js:gulpfile.js
var gulp = require('gulp');
var coffee = require('gulp-coffee'); // pluginの読み込み

gulp.task('coffee', function() {
  return gulp.src(['src/*.coffee']) // srcを指定
    .pipe(coffee())                 // 指定したファイルをJSにコンパイル
    .pipe(gulp.dest('dest'));       // dest先に出力する
});

// default タスクの時にcoffeeタスクを実行する
gulp.task('default', ['coffee'], function() {
  console.log('done');
});
```

gulp APIには、上のように`pipe`を使うことによって
タスクを順番に記載していくことが出来る。

例えば、上でJS化したファイルを圧縮して、結合したい場合は
[gulp-uglify](https://github.com/terinjokes/gulp-uglify/)や[gulp-concat](https://github.com/wearefractal/gulp-concat)を使う。

```js:gulpfile.js
var gulp = require('gulp');
var coffee = require('gulp-coffee');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');

gulp.task('coffee', function() {
  return gulp.src(['src/**/*.coffee'])
    .pipe(coffee())
    .pipe(uglify())             // minifyして...
    .pipe(concat('all.min.js')) // 結合する
    .pipe(gulp.dest('dest'));
});

gulp.task('default', ['coffee'], function() {
  console.log('done');
});
```

# API

`gulp`はいくつかAPIを提供している。

https://github.com/gulpjs/gulp/blob/master/docs/API.md

## `gulp.src(globs[, options])`

pipeに渡したいファイルを [node-glob](https://github.com/isaacs/node-glob)形式で指定する。

## `gulp.dest(path)`

pipeで処理しきったものの出力先。
下みたいに、pipeの途中で一回ファイルに書き出すことも出来る。

```js:gulpfile.js
gulp.src('./client/templates/*.jade')
  .pipe(jade())
  .pipe(gulp.dest('./build/templates'))
  .pipe(minify())
  .pipe(gulp.dest('./build/minified_templates'));

```

## `gulp.task(name[, deps], fn)`

タスクの定義の仕方。
`deps` でここで定義したタスクを走らせる前に実行するタスクを指定出来る。**配列指定**。

### 非同期タスクのサポート

`fn`の中の処理が非同期処理の場合は
`callback`を引数に持つ、`stream`を返す、`promise`を返すなど行う。
逆にちゃんと設定しないと、期待した順にタスクが動かない場合がある。

```js:gulpfile.js
gulp.task('task1', function(cb) {
  setTimeout(function() {
    console.log('task1');
    cb();
  }, 1000);
});

gulp.task('task2', function() {
  setTimeout(function() {
    console.log('task2');
  }, 1000);
});

gulp.task('foo', ['task1'], function() { // ‘task1’, ‘complete'
  console.log('complete');
});
gulp.task('bar', ['task2'], function() { // ‘complete’, ’task2'
  console.log('complete');
});
```

## `gulp.watch(glob [, opts], tasks)`

watchは`gulp`のAPIに定義されてる。

```js:gulpfile.js
gulp.task('check', function() {
  var watcher = gulp.watch('src/**/*.coffee', ['task1']); // watchしたいファイルと実行タスクを指定
  watcher.on('change', function(event) {                      // 変更時のイベント
    console.log('File '+event.path+' was '+event.type+', running tasks...');
  });
});

gulp.task('default', ['coffee', 'check'], function() {
  console.log('done');
});
```

イベントは
`added` `changed` `deleted` などがある。

# 所感

* Gruntの後発なので、コンパクトな構成
  * Gruntのあのちょっと独自なJSON形式がない
* プラグインがどれだけあるかは、ちょっと調べる。