jadeとstylusとcoffeeのgruntを作ってみた

## はじめに
タイトルの通りですが、jadeとstylusとcoffeeを監視、コンパイルして、圧縮してビルドするGruntfileを作りました。その他にも色々機能がありますので紹介します。

## ファイル構成
```text
Gruntfile.coffee
package.json
src/
  jade/sample.jade
  stylus/sample.styl
  coffee/sample.coffee
  images/sample.jpg
```
## Getting Started
package.jsonを任意の場所に置いて、npm installします。
必要なnode_modulesがインストールされます。
grunt-contribで足りないものも含まれています。

```json:package.json
{
  "name": "grunt-jade-stylus-coffee",
  "version": "0.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": "",
  "author": "",
  "license": "BSD",
  "devDependencies": {
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-contrib-compass": "~0.6.0",
    "grunt-contrib-clean": "~0.5.0",
    "grunt-contrib-sass": "~0.5.1",
    "grunt-contrib-htmlmin": "~0.1.3",
    "grunt-contrib-csslint": "~0.1.2",
    "grunt-contrib-cssmin": "~0.6.2",
    "grunt-contrib-jst": "~0.5.1",
    "grunt-contrib-coffee": "~0.7.0",
    "grunt-contrib-qunit": "~0.3.0",
    "grunt-contrib-connect": "~0.5.0",
    "grunt-contrib-requirejs": "~0.4.1",
    "grunt-contrib-jshint": "~0.6.5",
    "grunt-contrib-jasmine": "~0.5.2",
    "grunt-contrib-uglify": "~0.2.7",
    "grunt-contrib-handlebars": "~0.5.12",
    "grunt": "~0.4.2",
    "grunt-contrib-compress": "~0.5.3",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-contrib-stylus": "~0.8.0",
    "grunt-contrib-jade": "~0.8.0",
    "grunt-contrib-imagemin": "~0.3.0",
    "grunt-contrib-less": "~0.7.0",
    "grunt-contrib-nodeunit": "~0.2.2",
    "grunt-contrib-yuidoc": "~0.5.0",
    "grunt-contrib": "~0.8.0",
    "matchdep": "~0.3.0",
    "grunt-coffeelint": "0.0.7",
    "grunt-simple-mocha": "~0.4.0",
    "grunt-autoprefixer": "~0.4.1",
    "grunt-styleguide": "~0.2.12"
  }
}
```
```shell-session
npm install
```
```coffeescript:Gruntfile.coffee
module.exports = (grunt) ->

  # load all grunt tasks
  (require 'matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks)

  _ = grunt.util._
  path = require 'path'

  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')
    # Metadata.
    banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today(\'yyyy-mm-dd\') %>\n' + '<%= pkg.homepage ? \'* \' + pkg.homepage + \'\\n\' : \'\' %>' + '* Copyright (c) <%= grunt.template.today(\'yyyy\') %> <%= pkg.author.name %>;' + ' Licensed <%= _.pluck(pkg.licenses, \'type\').join(\', \') %> */\n'

    dir:
      src: 'src'
      jade: 'jade'
      styl: 'stylus'
      coffee: 'coffee'
      images: 'images'
      js: 'js'
      css: 'css'
      img: 'images'
      vendors: 'vendors'
      dist: 'dist'
      build: 'build'
      docs: 'docs'
      test: 'test'

    jade:
      dist:
        options:
          pretty: true, #htmlをインデント表記させる
        expand: true
        cwd: '<%= dir.src %>/<%= dir.jade %>'
        src: '**/*.jade'
        dest: '<%= dir.dist %>/'
        ext: '.html'

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

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

    htmlmin:
      build:
        options:
          removeComments: true
          collapseWhitespace: true
        expand: true
        cwd: '<%= dir.dist %>'
        src: '**/*.html'
        dest: '<%= dir.build %>'
        ext: '.html'

    cssmin:
      build:
        expand: true
        cwd: '<%= dir.dist %>/<%= dir.css %>'
        src: '**/*.css'
        dest: '<%= dir.build %>/<%= dir.css %>'
        ext: '.css'

    uglify:
      options:
        banner: '<%= banner %>'
        sourceMap: (path) ->
          path + '.map'
      build:
        expand : true
        src: '<%= dir.build %>/**/*.js'

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

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

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

    simplemocha:
      dist:
        src: '<%= dir.test %>/<%= dir.coffee %>/*.coffee'
      options:
        globals: ['should']
        timeout: 3000
        ignoreLeaks: false
        grep: '*-test'
        ui: 'bdd'
        reporter: 'tap'

    watch:
      jade:
        files: '<%= dir.src %>/**/*.jade',
        tasks: 'jade:dist'
      stylus:
        files: '<%= dir.src %>/**/*.styl'
        tasks: ['stylus:dist', 'autoprefixer:dist', 'styleguide:dist']
      coffee:
        files: '<%= dir.src %>/**/*.coffee'
        tasks: 'coffee:dist'
      images:
        files: ['<%= dir.src %>/**/*.{gif,jpeg,jpg,png,svg,webp}']
        tasks: ['clean:images', 'copy', 'imagemin']
      vendors:
        files: ['<%= dir.src %>/<%= dir.vendors %>/']
        tasks: ['copy:vendors']
      livereload:
        options:
          livereload: '<%= connect.options.livereload %>'
        files: [
          '<%= dir.dist %>/*.html',
          '<%= dir.dist %>/**/*.css',
          '<%= dir.dist %>/**/*.js',
          '<%= dir.dist %>/**/*.{gif,jpeg,jpg,png,svg,webp}'
        ]

    connect:
      options:
        port: 9000
        livereload: 35729
        hostname: 'localhost'
      livereload:
        options:
          open: true
          base: ['<%= dir.dist %>']

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

    yuidoc:
      dist:
        name: '<%= pkg.name %>'
        description: '<%= pkg.description %>'
        version: '<%= pkg.version %>'
      options:
        paths: '<%= dir.src %>/<%= dir.coffee %>/'
        outdir: '<%= dir.docs %>/<%= dir.js %>'
        syntaxtype: 'coffee'
        extension: '.coffee'

    styleguide:
      dist:
        files:
          #'<%= dir.docs %>/<%= dir.css %>': '<%= dir.src %>/<%= dir.styl %>/**/*.styl'
          '<%= dir.docs %>/<%= dir.css %>': '<%= dir.dist %>/<%= dir.css %>/**/*.css'
          #'<%= dir.docs %>/<%= dir.css %>': '<%= dir.src %>/<%= dir.styl %>/**/*.sass'

    clean:
      dist:
        src: [
          '<%= dir.dist %>/**/*.html',
          '<%= dir.dist %>/<%= dir.js %>/**/*.js',
          '<%= dir.dist %>/<%= dir.css %>/**/*.css',
          '<%= dir.build %>',
          '<%= dir.docs %>'
        ]
      docs:
        src: '<%= dir.docs %>'
      images:
        src: ['<%= dir.dist %>/<%= dir.img %>']

  grunt.registerTask 'default', [
    'clean',
    'coffeelint',
    'simplemocha',
    'yuidoc'
    'jade:dist',
    'stylus:dist',
    'autoprefixer',
    'styleguide',
    'coffee:dist',
    'copy:img',
    'copy:vendors',
    'imagemin'
  ]
  grunt.registerTask 'w', [
    'default',
    'connect',
    'watch',
    'jshint',
  ]
  grunt.registerTask 'compile', [
    'clean',
    'coffee:dist',
    'jade:dist',
    'stylus:dist'
  ]
  grunt.registerTask 'build', [
    'default',
    'copy:build'
    'htmlmin:build',
    'cssmin:build',
    'uglify'
  ]
  grunt.registerTask 'c', ['compile']
  grunt.registerTask 'docs', ['clean:docs', 'yuidoc', 'styleguide']
```

## 使い方
デフォルトのコマンドで、jade,stylus,coffeeがコンパイルされ、distディレクトリの中に配置されます。

```shell-session
grunt
```

```text
Gruntfile.coffee
package.json
dist/
  sample.html
  js/
    sample.js
  css/
    sample.css
  img/
    sample.jpg
src/
  jade/sample.jade
  stylus/sample.styl
  coffee/sample.coffee
  images/sample.jpg
```

grunt wで監視します。ブラウザが立ち上がり、jade,stylus,coffee,imagesディレクトリの中身に変更があれば自動でリロードします。

```shell-session
grunt w
```

grunt buildでリリースビルドします。buildディレクトリの中に配置され、各ファイルはminifyされます。画像も圧縮されます。

```shell-session
grunt build
```

### coffeelint
coffee-scriptの文法チェックです。デフォルトと監視時にチェックが入ります。
### simplemocha
simplemochaで簡単なJSテストをします。
### autoprefixer
CSSでベンダープレフィックスを自動でつけてくれる機能です。

```
selector {
  transition: transform 1s;
}
```

と書けば、grunt後に、

```
selector {
  -webkit-transition: -webkit-transform 1s;
  transition: transform 1s;
}
```

と書きだされます。
## imagemin
画像のファイル容量を圧縮します。設定は、optimizationLevelでデフォルトは7です。
細かい設定は、下記のURLから。
[grunt-contrib-imagemin](https://github.com/gruntjs/grunt-contrib-imagemin#options)
## uglify
JSファイルの難読化、圧縮をします。ビルド時にSourceMapというファイルが出ます。
[Introduction to JavaScript Source Maps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/?redirect_from_locale=ja)