[Grunt & Yeoman] Grunt タスクランナーで自動化する

インストールして動かしてみます。

インストール

% sudo npm install -g grunt-cli

sudo つけないと不具合が起きたりするのだろうか?
プロジェクトのディレクトリや git init 等を準備しておく。

% mkdir gruntSample
% cd gruntSample
% git init

package.json

npm init で対話的に作成してしまう。

% npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (gruntSample)
version: (0.0.0) 0.0.1
description: Sample Project
entry point: (index.js) Gruntfile.coffee
test command: grunt watch
git repository: (git://github.com/DriftwoodJP/gruntSample.git)
keywords: sample
author: deadwood
license: (BSD-2-Clause) MIT
About to write to /Users/****/projects/gruntSample/package.json:
{
  "name": "gruntSample",
  "version": "0.0.1",
  "description": "Sample Project",
  "main": "Gruntfile.coffee",
  "scripts": {
    "test": "grunt watch"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/DriftwoodJP/gruntSample.git"
  },
  "keywords": [
    "sample"
  ],
  "author": "deadwood",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/DriftwoodJP/gruntSample/issues"
  }
}
Is this ok? (yes)

他にも ”readmeFilename”: “README.md”, のようなものが色々あるよう。
package.json に従って grunt をインストールする。

% npm install grunt --save-dev
:
grunt@0.4.1 node_modules/grunt
├── which@1.0.5
├── dateformat@1.0.2-1.2.3
├── eventemitter2@0.4.13
├── colors@0.6.2
├── hooker@0.2.3
├── async@0.1.22
├── lodash@0.9.2
├── coffee-script@1.3.3
├── underscore.string@2.2.1
├── findup-sync@0.1.2 (lodash@1.0.1)
├── iconv-lite@0.2.11
├── nopt@1.0.10 (abbrev@1.0.4)
├── rimraf@2.0.3 (graceful-fs@1.1.14)
├── minimatch@0.2.12 (sigmund@1.0.0, lru-cache@2.3.1)
├── glob@3.1.21 (inherits@1.0.0, graceful-fs@1.2.3)
└── js-yaml@2.0.5 (esprima@1.0.4, argparse@0.1.15)

プラグインのインストール

grunt とプラグインを利用するためには、package.json の devDependencies 内に列挙する必要がある。
npm install <module> --save-dev コマンドを使用することで、ローカルに<module> をインストールするだけで無く、 devDependencies内に自動的に~を使用したバージョン範囲の指定を追加する。

grunt-contrib

grunt-contrib をインストールします。

% npm install grunt-contrib --save-dev
.
├── README.md
├── node_modules
│   ├── grunt
│   ├── grunt-contrib
│   ├── grunt-contrib-clean
│   ├── grunt-contrib-coffee
│   ├── grunt-contrib-compass
│   ├── grunt-contrib-compress
│   ├── grunt-contrib-concat
│   ├── grunt-contrib-connect
│   ├── grunt-contrib-copy
│   ├── grunt-contrib-csslint
│   ├── grunt-contrib-cssmin
│   ├── grunt-contrib-handlebars
│   ├── grunt-contrib-htmlmin
│   ├── grunt-contrib-imagemin
│   ├── grunt-contrib-jade
│   ├── grunt-contrib-jasmine
│   ├── grunt-contrib-jshint
│   ├── grunt-contrib-jst
│   ├── grunt-contrib-less
│   ├── grunt-contrib-nodeunit
│   ├── grunt-contrib-qunit
│   ├── grunt-contrib-requirejs
│   ├── grunt-contrib-sass
│   ├── grunt-contrib-stylus
│   ├── grunt-contrib-uglify
│   ├── grunt-contrib-watch
│   └── grunt-contrib-yuidoc
└── package.json
28 directories, 2 files

プラグインのアップデート

以下で確認とアップデートができるよう。

% npm outdated
% npm update

タスクを登録する

Gruntfile.js に記載したタスクが登録される。
.coffee ファイルも利用できる。
雛形を生成するようなコマンドあるんでしょうかね?

Gruntfile.js (Gruntfile.coffe)

少し書いて確認してみる。

module.exports = function(grunt) {
  'use strict';
  //グラントタスクの設定
  grunt.initConfig({
    //watchの設定
    watch: {
      dev: {
        files: ["sample.txt"]
      }
    }
  });
  //プラグインの読み込み
  // grunt.loadNpmTasks('grunt-contrib-watch');
  var pkg = grunt.file.readJSON('package.json');
  var taskName;
  for(taskName in pkg.devDependencies) {
    if(taskName.substring(0, 6) == 'grunt-') {
      grunt.loadNpmTasks(taskName);
    }
  }
  // タスクコマンドの設定
  grunt.registerTask('default', ['watch']);
};

module.exports = function(grunt)

すべての Grunt コードは、wrapper 関数内に書かねばならない。

grunt.initConfig

ここでタスクの登録・設定を指定する。
grunt foo で実行可能となる。

loadNpmTasks

プラグインをロードする。

grunt.loadNpmTasks('grunt-contrib-watch');

複数のプラグインを読み込む場合、package.json の設定を利用して、Script で読み込むこともできる。

  var pkg = grunt.file.readJSON('package.json');
  var taskName;
  for(taskName in pkg.devDependencies) {
    if(taskName.substring(0, 6) == 'grunt-') {
      grunt.loadNpmTasks(taskName);
    }
  }

registerTask

initConfig で設定したタスクをカンマ(,)区切りで複数登録することでまとめて実行できる。

grunt.registerTask('foo', ['cssmin', 'watch']);

この場合、cssmin と watch タスクが以下のコマンドで実行される。

% grunt foo

default は省略可能。

Gruntfile.coffe

Gruntfile は coffeescript で記述することが可能。
やっぱりこちらの方がスッキリですね。

module.exports = (grunt) ->
  'use strict'
  # グラントタスクの設定
  grunt.initConfig
    # watchの設定
    watch:
      dev:
        files: ['sample.html']
      prod:
        files: ['sample.txt']
  # プラグインの読み込み
  # grunt.loadNpmTasks 'grunt-contrib-watch'
  pkg = grunt.file.readJSON 'package.json'
  for taskName of pkg.devDependencies when taskName.substring(0, 6) is 'grunt-'
    grunt.loadNpmTasks taskName
  # タスクコマンドの設定
  grunt.registerTask 'default', ['watch']

上記のように書くと、grunt watch:dev:dev 内のみ実行される。

補遺

こういった製品もあるらしい。
用途によっては、まるっと導入した方が手っ取り早いのかもしれない。