grunt-express-serverを使って開発できるGruntfileを作ってみた

## はじめに
Node.jsをExpressで作る際に、app.js, routes, jade, stylus, publicの中にあるファイルなどを更新した際に、serverがrestartしてブラウザもreloadされる。ようなGruntfileを作りました。まぁまぁ開発が早くなるんちゃうかと思います。

## 環境
Node.js v0.10.26
Express v3.0.0
node-supervisor

テンプレートはJadeを使ってます。
CSSは、stylusからCSSを書き出してます。その際に、ベンダープレフィックスを追加するautoprefixerが動いてます。
JavaScriptファイルは全てcoffeeで書きます。
vendorsフォルダーは、distにコピーしているだけです。

## Nodeプロセス
node-supervisorを使って起動しますので、npm install -g node-supervisor してください。

## ファイル構成
```text
.
├── Gruntfile.coffee
├── app
│   ├── app.coffee
│   ├── bin
│   │   └── www
│   ├── public
│   │   ├── images
│   │   ├── javascripts
│   │   └── stylesheets
│   ├── routes
│   │   ├── index.coffee
│   │   └── user.coffee
│   └── views
│       ├── error.jade
│       ├── index.jade
│       └── layout.jade
├── node_modules
└── package.json
```
## Getting Started
package.jsonのあるディレクトリでnpm installします。
必要なnode_modulesがインストールされます。

```json:package.json
{
  "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "express": "^3.4.8",
    "static-favicon": "^1.0.0",
    "morgan": "^1.0.0",
    "cookie-parser": "^1.0.1",
    "body-parser": "^1.0.0",
    "debug": "^0.7.4",
    "jade": "^1.3.0"
  },
  "devDependencies": {
    "grunt": "^0.4.5",
    "grunt-autoprefixer": "^0.8.1",
    "grunt-connect-proxy": "^0.1.10",
    "grunt-contrib-clean": "^0.5.0",
    "grunt-contrib-coffee": "^0.10.1",
    "grunt-contrib-connect": "^0.8.0",
    "grunt-contrib-copy": "^0.5.0",
    "grunt-contrib-imagemin": "^0.7.1",
    "grunt-contrib-stylus": "^0.18.0",
    "grunt-contrib-watch": "^0.6.1",
    "grunt-express-server": "^0.4.17",
    "grunt-newer": "^0.7.0",
    "matchdep": "^0.3.0"
  }
}
```
```shell-session
npm install
```
```coffeescript:Gruntfile.coffee
'use strict'

proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest
mountFolder = folderMount = (connect, base) ->
  connect['static'] require('path').resolve(base)

listen = 8000
server = 3000

module.exports = (grunt) ->
  require('matchdep').filterDev('grunt-*').forEach grunt.loadNpmTasks
  grunt.initConfig

    dir:
      src: 'app'
      styl: 'stylesheets'
      coffee: 'javascripts'
      images: 'images'
      js: 'javascripts'
      css: 'stylesheets'
      img: 'images'
      vendors: 'vendors'
      dist: 'dist'
      build: 'build'
      docs: 'docs'
      test: 'test'

    stylus:
      dist:
        options:
          compress: false
        expand: true
        cwd: '<%= dir.src %>'
        src: '**/*.styl'
        dest: '<%= dir.dist %>'
        ext: '.css'

    coffee:
      dist:
        option:
          pretty: true
        expand: true
        cwd: '<%= dir.src %>'
        src: '**/*.coffee'
        dest: '<%= dir.dist %>'
        ext: '.js'

    # coffeeの文法チェック
    coffeelint:
      app: '<%= dir.src %>/**/*.coffee'

    # CSSのprefiexを補完
    autoprefixer:
      options:
        browsers: ['last 2 version', 'ie 8', 'ie 7', 'ie 6']
      dist:
        expand: true
        cwd: '<%= dir.dist %>'
        src: '**/*.css'
        dest: '<%= dir.dist %>'
        ext: '.css'

    # 画像の圧縮
    imagemin:
      options:
        optimizationLevel: 7
        pngquant: false
      dist:
        expand: true
        cwd: '<%= dir.dist %>/public/<%= dir.images %>'
        src: '**/*.{jpg,jpeg,gif}'
        dest: '<%= dir.dist %>/public/<%= dir.img %>'

    copy:
      jade:
        expand: true
        dot: true
        cwd: '<%= dir.src %>'
        dest: '<%= dir.dist %>'
        src: '**/*.jade'
      bin:
        expand: true
        cwd: '<%= dir.src %>/bin'
        dest: '<%= dir.dist %>/bin'
        src: '**'
      img:
        expand: true
        dot: true
        cwd: '<%= dir.src %>'
        dest: '<%= dir.dist %>'
        src: [
          '**/*.{gif,jpeg,jpg,png,svg,webp}',
        ]
      vendors:
        expand: true
        dot: true
        cwd: '<%= dir.src %>/public/<%= dir.vendors %>'
        dest: '<%= dir.dist %>/public/<%= dir.vendors %>'
        src: ['**']
      build:
        expand: true
        dot: false
        cwd: '<%= dir.dist %>/'
        dest: '<%= dir.build %>/'
        src: ['**']

    connect:
      front:
        options:
          host: 'localhost'
          port: listen
          middleware: (connect) ->
            [
              mountFolder(connect, '.')
              proxySnippet
            ]
          open:
            target: 'http://localhost:' + listen
          livereload: true

      proxies: [
        context: '/'
        host: 'localhost'
        port: server + ''
        https: false
        changeOrigin: false
      ]

    express:
      dev:
        options:
          background: true
          port: server
          cmd: 'supervisor'
          args: []
          script: '<%= dir.dist %>/bin/www'
          delay: 0

    watch:
      jade:
        files: '<%= dir.src %>/**/*.jade',
        tasks: 'newer:copy:jade'
      stylus:
        files: '<%= dir.src %>/**/*.styl'
        tasks: [
          'newer:stylus:dist',
          'newer:autoprefixer:dist',
          'newer:styleguide:dist'
        ]
      coffee:
        files: '<%= dir.src %>/**/*.coffee'
        tasks: 'newer:coffee:dist'
      images:
        files: ['<%= dir.src %>/**/*.{gif,jpeg,jpg,png,svg,webp}']
        tasks: ['newer:imagemin:dist', 'copy', 'imagemin']
      vendors:
        files: ['<%= dir.src %>/<%= dir.vendors %>/**']
        tasks: ['copy:vendors']
      express:
        files: [
          '<%= dir.dist %>/app.js'
          '<%= dir.dist %>/routes/**/*.js'
          '<%= dir.dist %>/views/**/*.jade'
        ]
        tasks: ['express:dev']
        options:
          livereload: true
      veiw:
        files: ['<%= dir.dist %>/public/**/*.{js,css}']

    clean:
      dist:
        src: [
          '<%= dir.dist %>'
        ]
      docs:
        src: '<%= dir.docs %>'

  grunt.registerTask 'server', [
    'configureProxies'
    'express:dev'
    'connect:front'
    'watch'
  ]

  grunt.registerTask 'default', [
    'clean'
    'stylus:dist'
    'autoprefixer'
    'coffee:dist'
    'copy:jade'
    'copy:img'
    'copy:bin'
    'copy:vendors'
    'imagemin'
  ]

  grunt.registerTask 'dev', [
    'default'
    'configureProxies'
    'express:dev'
    'connect:front'
    'watch'
  ]
```

## 簡単な使い方
デフォルトのコマンドは、coffeeファイルがJavaScriptファイルに、stylusファイルがCSSファイルに書きだされ、jadeはコピーされて、画像ファイルは圧縮されます。

```shell-session
grunt
```
grunt devで、ブラウザが立ち上がりページが表示されます。ファイル監視をし、ファイルに変更があれば、サーバーが再起動してブラウザもリロードします。

```shell-session
grunt dev
```