Grunt止めて、mincer止めて、Brunchに乗り換えた

web開発にはフロントエンドのビルドツールが必要。
coffeeスクリプトや、scssなどのメタ言語を使いたいならもちろんビルドをしてjsやcssに変換しないといけないし、もし仮にそれを使わなかったとしても、jsやcssの圧縮をするべきなので、ビルドをするソリューションあるべき。
(どっちみちビルドという工程をやることになるなら、メタ言語というものは使った方が良い。とおもう)

grunt、mincer、brunch を使ってみて、結局brunchにしたので比較したことをメモしておく。

## Grunt

http://gruntjs.com/
gruntは、けっこう名前をよく聞くビルドツール。
処理そのものはプラグインとして組み込んでおき、色々な処理たちをパイプライン的に順番に並べる設定ファイルを書く。

ファイル変更の監視や、開発webサーバをgruntタスクとして立ち上げることもできるので、rubyで言うところの rake + guard + webrick がこれひとつで大丈夫


### Gruntの気にいらなかったとこ

* watchが素朴な感じで、ファイルの変更を検知 → 設定しておいたタスク実行。これだけなので、よっぽどの工夫をしない限り、coffeeスクリプトをファイル一個保存しただけなのに、プロジェクト内の全部のcoffeeがコンパイルされるという動作をする。
* 僕は暇さえあればファイルを保存しているので、コンパイル走りすぎてうざいから使うのやめた。
* これを回避する良いやりかたがあれば教えてほしい。

## mincer

https://github.com/nodeca/mincer
Gruntとはアプローチが違い、あらかじめビルドしておくのではなく、jsやcssへリクエストが飛んできたタイミングで、ビルドしたものを返却する仕組み。
mincerをサーバとして実行して待機させておくか、node.js製のサーバに組み込んで使う。
RailsのAssets pipelineとまったく同じアプローチ。本家にも、"port of sprockets" と書いてある。

### mincerの気にいらなかったとこ

* サーバサイドのcoffeeを、同じ枠組みでコンパイルする手段がない。
* 開発環境では、たくさんのjavascript(css)が圧縮されずに1つずつリクエストされるので、リロードしたとき遅い。(一方、Railsは、turbolinks使えば快適だと思われる)


## Brunch

http://brunch.io/

Gruntと似たような機能を持っているビルドツール。

> Brunch is an ultra-fast HTML5 build tool

と書いてある。
なにがウルトラfastかというと、`brunch w` でファイルを監視し、ファイルの変更を検知されたとき、変更されたファイルのみをビルドしてくれるという、私のような暇さえあればファイルを保存している病気がある人にとっては嬉しい挙動をしてくれるところ。

基本的には、HTML側では、開発環境/本番環境できりかえずに、`<script src="app.js></script>` みたいな1つのファイルを読みこむようにしておく。

```bash
$ brunch w -s
`17 Nov 23:07:38 - info: compiled circle.coffee and 9 cached files into app.js in 136ms`
```
みたいに、ウォッチしていると、メッセージがコンソールに出て、ちゃんと余計なものはコンパイルしてない賢いことをした結果、app.jsをつくったよ。と教えてくれる。

また、Gruntより良いなと思ったところがいくつか
* bowerとの連携が良い感じ。勝手にbower.json を読んでくれる。
    * bowerでいれたスクリプトに、`main` キーが設定されていない場合は、自分のプロジェクト内のbower.jsonでoverrideしておく。
    * クライアントサイドの外部スクリプトに関する設定が、ほぼほぼbower.jsonだけで済む。
* 設定ファイルがもっと短く書ける
* liverelod的なことがBrunchだけでできる。(アドオンとかいらない)
* Yoemenのような雛形作成機能がある。これはGruntにはない。

### サーバサイドのcoffeeスクリプトをBrunchで監視

Brunchの設定ファイルde、`server` というキーに色々と設定することで、サーバサイドのcoffeeスクリプトも監視してコンパイルしてくれる。
変更されたらサーバを再起動。。みたいな動作は、残念ながら自分で色々設定しないといけないようだったが、
`brunch new gh:jerfowler/ExpressBrunchJade`
とかして雛形つくると、express + 変更あったら再起動　の設定が同梱されている。
自分は上記をベースにして、いらないところ色々抜いて使ってる。


```coffeescript:config.cofffee
exports.config =
  paths:
    public: 'public'
    watched: ['src']

  modules:
    wrapper: 'amd'

  # See docs at http://brunch.readthedocs.org/en/latest/config.html.
  files:
    javascripts:
      defaultExtension: 'coffee'
      joinTo:
        'js/app.js': /^src\/client/
        'js/vendor.js': /^bower_components/
    templates:
      defaultExtension: 'hbs'
      joinTo: 'js/app.js'

  server:
    path: 'brunch_server'
    port: 3000
    base: '/'
    app: 'src/server/app'
    persistent: true
    interval: 100
    watched: ['src/server']
    ignore: /(^[.#]|(?:~)$)/
    source: /.*\.coffee$/
    tester:
      enabled: false

  plugins:
    autoReload:
      enabled:
        css: on
        js: on
        assets: off
      port: [1234, 2345, 3456]
```

```coffeescript:brunch_server.coffee
{exists} = require('fs')
{EventEmitter} = require('events')
{resolve, join} = require('path')
{filter} = require('async')
http = require('http')
cordell = require('cordell')

{config} = require('./config')

class BrunchServer extends EventEmitter
  constructor: (config) ->
    @config = {}
    @config[k] = v for k, v of config.server
    throw 'Must specify an app location under config.server.app' unless @config.app?
    @app = require(resolve(@config.app))
    @server = http.createServer(@app)
    # @_debug = if @config.debug? require('debug')("#{@config.debug}") else ->

  start: (port, callback) ->
    @server.listen port, callback
    if @config.watched?
      filter @config.watched, exists, (files) =>
        @ranger = cordell.ranger files, @config
        @ranger.on 'end', (files, stats) =>
          setTimeout =>
            @ranger.on 'add', =>
              @reload()
            @ranger.on 'rem', =>
              @reload()
            @ranger.on 'change', =>
              @reload()
          , 1000
      @emit 'start', @

  stop: (fn) ->
    console.log 'Stopping...'
    @server.close fn
    @watcher.close()
    @emit 'stop', @

  reload: ->
    console.log 'Reloading...'
    @app = require(resolve(@config.app))
    @emit 'reload', @

  close: (fn) ->
    @stop fn

module.exports = exports = BrunchServer

module.exports.startServer = (port, path, callback) ->
  server = new BrunchServer(config)
  # io = require('socket.io').listen server.server, logger: server.logger
  # io.set 'log level', 2 
  # sockets = require('./express/sockets')(io)

  # server.on 'reload', ->
  #     sockets.emit '/brunch/reload', 1000
  #     sockets.destroy()
  #     sockets = require('./express/sockets')(io)

  server.start(port, callback)
  server
```
cofig.coffeeは、Gruntfileよりだいぶ短くなったんだよね