Gruntとの上手な付き合い方 〜 JSおくのほそ道 #006

こんにちはほそ道です。
今回からビルドツールを取り上げます。
ツールの手順的なものは既に巷にあふれているので、
振り切って、さらに研究室っぽく本質的なアーキテクチャを探って参ります。

バージョンは下記です
grunt 0.4.5
grunt-cli v0.1.13

[目次はこちら](http://qiita.com/setzz/items/ad9a9c99a4fda041a563)

# Grunt概要
[本家](http://gruntjs.com/)のサイトを見てみます。
冒頭には下記のような事が書いてあります。

```text
GruntはJavaScriptのタスクランナーなんだぜ。
なんでタスクランナー使うのか？一言で言うと「自動化」だね。
めんどくっさい繰り返し作業の量を減らし、簡単にしてくれる。
ミニファイ、コンパイル、ユニットテスト、リンティング(静的コードチェック)とかとか。
設定を一発やっとけばあとは大体タスクランナーがやってくれるんだよ。
```

ほそ道的にはとほれぼれするようなナイスな導入だと思います。
いろいろとプラグインが増えてくると何でも出来るツールみたいになっていきがちだと思いますが
本質は「自動化」。
これに尽きるものだと思います。
ちなみにGruntはタスクランナーと言ってますがビルドツールと同じものととらえてます。

# 動かしてみる

uglifyプラグインを使ってjsファイルをミニファイするタスクのサンプルです。
`grunt`コマンドのインストールは`npm install -g grunt-cli`でできます。

- プロジェクトの作成

```bash:bash
mkdir project_name
cd project_name
touch Gruntfile.js
npm init
npm install grunt --save-dev
npm install grunt-contrib-uglify --save-dev
```

- 設定ファイルの記述

```js:Gruntfile.js
module.exports = function(grunt) {
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.initConfig({
    uglify: {
      target1: {
        src: 'foo.js',
        dest: 'foo.min.js'
      }
    }
  });
  grunt.registerTask('default', ['uglify']);
};
```

- 実行

```bash:bash
npm install grunt-contrib-uglify
grunt
```

これでファイルがミニファイされfoo.jsがfoo.min.jsになります。
`grunt.registerTask('default', ['uglify']);`の['uglify']の部分を自作の関数に置き換える事も出来ます。

# 奥の細道:Gruntとの上手な付き合い方

それでは本日のお題であるGruntとの上手なお付き合いについて

## 調べ物でハマらない為に
さて、ビルドツール全般に言える事なのですがワタシは結構ストレスをためる事が多いです。
具体的には

```text
「やりたい事をビルトインやプラグインで提供しているか調べる」→
「ない」→
「ググる」→
「やっぱりない」→
「カスタマイズまたはプラグイン作成または諦める」
```

みたいなパターンに陥ると非常に時間がもったいないんですね。
調べ物は効率的に行いたいものです。


## オススメな調査方法
ちょっと変わった事をやりたいときに出来るのか？みたいなことを調べるにはむやみにググるより

- [APIリファレンス](http://gruntjs.com/api/grunt)
- [公式プラグインリスト](http://gruntjs.com/plugins)

を探るのが良いんではないかと思います。

しかし、やっぱりそれでもやりたい事の解決方法が見つからない時、ハマる時はハマります。

では、どうすれば良いかと言うと、ほそ道的にはある程度の基礎概念の習得が必要なんではないかと思う訳です。
「このAPIパラメータに配列食わせて行けるのか？」とか「コンフィグのデータ型はどこまでいじれるのか？」
など、ソースコードのどの辺を見れば良いかをなんとなーく理解しておくと
いける/いけないの判断ふくめ調査コストが圧倒的に減ると思います。

## コアの動きを理解する
### Grunt概念図作ってみました(クラス関連図的な)
というわけで理解しやすいように概念図を作ってみました。
端折りながら大事そうな部分だけ抽出しております。
間違ってるところがあるかもしれませんが、既存のそれっぽい画像が無かったので
「やって！TRY」の心意気です。

![スライド1.jpg](https://qiita-image-store.s3.amazonaws.com/0/39330/e3a95162-7a62-85c6-0bbe-3af4995a148b.jpeg)

### 解説・補足
図の長ったらしいヤツは下記のように読み替えます
※gruntコマンド→[コマンド]
※grunt.util.task.Task.prototype.start→[start関数]
※grunt.util.task.Task._queue(private)→[内部キュー]

- コマンドが実行されると
    - (1-1)カレントディレクトリの`node_modules/grunt/lib/grunt.js`がrequireされる
        - grunt.jsからgruntオブジェクトが生成され、そこに`./grunt/`ディレクトリ配下の機能が追加される
    - (1-2)taskオブジェクトはGruntfile向けの関数インターフェースを提供する
- `Gruntfile.js`にて
    - (2-1)`grunt.initConfig`した内容は`grunt.config.data`オブジェクトに保存される
    - (2-2)`grunt.registerTask`した内容は[内部キュー]に保存される
- コマンドラインにて
    - (3-1)引数にタスク名を指定すると`grunt.cli.tasks`配列に保存される
        - コマンドライン引数を省略すると自動的に「default」という1タスクが保存される
    - (3-2)[コマンド]はgruntオブジェクトの状態が整うと`grunt.cli`関数を実行する
- (4)`grunt.cli`関数は[start関数]にコマンドライン引数を渡して実行する
    - start関数はコマンドライン引数と[内部キュー]からタスクを取り出して一致するタスクを実行する

と、いったところです。

オブジェクト指向的な権限分離や抽象化が多く複雑に感じますねぇ。。

# まとめ
今回は以上です。ほそ道的なGruntとの付き合い方をまとめておきます。

- ビルドツールの本質は自動化にある！一回仕組みを作ってしまえば良い。
- 仕組みづくり要件次第では結構メンドイ。むやみにググるより然るべきドキュメントで本質的に調べましょう。
- 長い目で見るとちゃんとアーキテクチャを理解しておくとハマらずに扱える。

次回はGrunt対抗馬と噂の[gulpを紹介](http://qiita.com/setzz/items/428479aba3aebeb82c42)します。
せっかくなので今回同様に概念図を作ってみようかと思ってます。