gruntを知らない人がgulpを使ってみた

Node.jsを初めて5日目。

#前置き
いろんなNode関連のサイトを徘徊していると、gruntとか、gulpとかいう言葉が登場します。
しかし私はいずれの言葉もよく知りません。
とりあえず理解できたのは、「いずれもタスクを管理する」ものであること、
また、gulpのほうが新しく、トレンドになりつつあること。

とりあず覚えて損はなさそうなので、試してみます。
いろんな解説サイトがあるけど、まずは、[本家のドキュメント](https://github.com/gulpjs/gulp/blob/master/docs/API.md)を見ながら進めてみます。


#インストール
1.グローバルにインストール

````js
npm install --global gulp

````

2.現在のプロジェクトにインストール

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

````

3.gulp.jsを作成する

````js
var gulp = require('gulp');

gulp.task('default', function() {
  // place code for your default task here
　//デフォルトのタスクを何かかけ
});
````


4.gulpを実行する

````js
gulp
````

ちなみに、`default`と書いた部分には任意の名前が付けられるようです。
もし`test`という名前にしたならば、gulpを実行する際に、
`gulp test`とすればよさそうです。

#gulpで何をするのか

さて、これで一体何をするのでしょうか？
とりあえずこんなことをしてみたいと思います。
####あるフォルダにあるJavaScriptファイルを圧縮する

下記コードでそれができます。

````js
//uglifyは、javascriptファイルを圧縮してくれるプログラムです。
//事前に `npm install gulp-uglify`を実行し、インストールしておく必要があります。
var uglify = require('gulp-uglify');
var gulp = require('gulp');

gulp.task('uglify', function() {
    gulp.src('js/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('js/min')) 
});

````

さて、上記を実行するには、
`gulp uglify`とコマンドを入力して実行します。
すると、jsフォルダ内の.js ファイルがすべて圧縮され、js/minフォルダに作成されます。
これは便利ですね。

でも、どうせならファイルが変更されたら勝手に圧縮してほしいものです。
ファイルが変更されたら何かを実行したい場合は、*watch*が使えます。
上のコードに少しだけ、書き加えます。

````js
gulp.task('uglify', function() {
    gulp.watch('js/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('js/min')) 
});

gulp.task('watch',function(){
    gulp.watch('js/*.js',['uglify']);
});

````

gulp.watch()の第二引数に定義したタスク名を指定しています。
コンソールで`gulp watch`と入力すると、待ち状態になると思います。
この状態でjsフォルダ内にあるjsファイルを編集すると、
`uglify`タスクが呼ばれて、jsフォルダ内のjsファイルをすべて圧縮、コピーしてくれます。

これは便利ですね。

このように、gulpを使うと、あらかじめ決まっている処理をタスクという形で定義しておき、
実行することができるのですね。

#サーバーを自動で再起動してみる。

サーバー再起動が必要なファイルを編集したら、勝手に再起動してほしいですね。
こんな感じでできそうです。

````gulpfile.js

var gulp = require('gulp');
var spawn = require('child_process').spawn;
var server;

gulp.task('server',function(){
    if(server){
         //サーバーを終了
         server.kill('SIGKILL');
    }
     //サーバーを起動
     server = spawn('node',['./bin/www']);
    
})

gulp.task('watch',['server'],function(){
    gulp.watch('js/*.js',['server']);
});

````

上記を`gulp watch`として、コンソールから起動すると

1.'server'タスクの起動と同時に、jsフォルダ以下のjsファイルを監視
2.ファイルに変更があったら、'server'タスクを実行

となります。

##child_process
ここでは、child_processというモジュールを使っています。
簡単に言えば、これで外のプログラムを起動したりできます。
「spawn」は、「産む」とかいう意味です。

例えば

````js
var spawn = require('child_process').spawn;
spawn('ping',['127.0.0.1']);
````

これを実行すると、コンソール上でpingを打った場合と同じことが起こります。
第一引数がプログラム名、第二引数には、プログラムに渡す引数を配列で指定します。

起動したプログラム（プロセス）終了するときは

`kill('SIGKILL');`とすれば終了します。

##他のタスクの実行
ところで、gulp.watchを実行すると、ファイルの変更があった場合には指示した命令を実行してくれますが、watch開始と同時に他のタスクを実行するには

````js
gulp.task('watch',['server'],function(){
````

というように、第二引数、起動したいタスク名を配列で指定します。

##npm startの中身
`server = spawn('node',['./bin/www']);`
とありますが、これは`npm start`の中身です。
ここまで、`npm start`として、expressを起動していましたが、
これはプロジェクトのルートフォルダにある「package.json」に何をするかが定義してあります。

package.jsonをみると

````js
  "scripts": {
    "start": "node ./bin/www"
  },
````

と書いてあります。

ですので、これをspawnに渡して

````js
spawn('node',['./bin/www'])
````
として起動しています。
※spawn('npm',['start'])でも動きそうですが、私はWindowsでnode.jsを使用しています。
windowsの場合、npmはnpm.cmdであり、バッチファイルです。
これはspawnでは起動できません。(spawnで起動できるのはwindowsではexeだけらしい)
どうしてもnpm経由で起動するなら、

````js
spawn('cmd', ['/s', '/c', '"npm"']
````

とすればイケそうですが、終了時にコマンドは終了するが、プロセスが残る、ということがあるとのこと。この問題についは[ココ(英語)](https://github.com/joyent/node/issues/2318)で語られています。試してはいないです。

##コンソールにエラー出力する
ただしこれだと、expressで出力されるエラーや、console.log(・・・)とした情報は、コンソールに出力されません。
出力するには、下記をgulpfileに追記しておきます。

````gulpfile.js
     console.logとかをハンドル
     server.stdout.setEncoding('utf8');
     server.stdout.on('data',function(data){
         console.log(data);
     });
     //エラーをハンドル
     server.stderr.setEncoding('utf8');
     server.stderr.on('data',function(data){
         console.log(data);
     });
````

##終わり
細かいことを抜きにすれば、これだけで、ファイル監視+サーバー再起動を実施することがき、ctrl+C npm start　とコンソールに入力する手間が省けますね。