2013年4月12日金曜日

Gruntの導入メモ

Grunt

Gruntを使ってみて便利だったのでメモ。

1. Grunt-CLIインストール

macで作業する前提です。
投稿時のバージョン
  • grunt-cli v0.1.6
  • grunt v0.4.1
Gruntはnode.jsのパッケージマネージャーnpmでインストールします。

事前にnode.jsのインストールが必要ですがここでは割愛。

以前のバージョン(0.3.x.)のGruntが入っている場合はアンインストールしておきます。

$ sudo npm uninstall -g grunt
そしてインストールします。

$ sudo npm install -g grunt-cli

2. プロジェクトの作成&準備

プロジェクトのフォルダを作成します。ここでは例として「grunt-test」とします。

そしてターミナルで作成したフォルダへ移動します。
$ cd path/to/grunt-test
macの場合は、“cd ”と入力した後にフォルダアイコンをターミナル画面内にドラッグアンドドロップすれば長いパス名でも楽チンです。





そしてREADME.mdというマークダウン形式のファイルを作成します。
なくても問題ないとは思いますが警告が表示されたりするので作っておきます。

何も書かれていないと同様に警告が出るので、適当にプロジェクト名を

#grunt-test
のように入力し、保存します。

ターミナルに戻り、

$ npm init
と入力します。すると、対話形式でプロジェクト名やプロジェクトのバージョンを聞かれるので入力します。

変更しない項目はそのままEnterを押していきます。するとpackage.jsonというファイルが作成されます。

package.json

{
  "name": "grunt-test",
  "version": "1.0.0",
  "description": "grunt-test",
  "main": "index.js",
  "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": "",
  "author": "",
  "license": "BSD"
}
このような中身になっていると思います。package.jsonは、プロジェクト内のパッケージなどを管理する情報が書かれたjsonファイルです。現時点ではパッケージを何もインストールしていないのでこのような状態です。

3. Grunt・Pluginのインストール

次はGruntとGruntのプラグインをインストールします。

$ npm install grunt grunt-contrib --save-dev
末尾の--save-devは、先程作成したpackage.jsonにインストールしたプラグインの情報を保存するためのもので、必ず付けるようにします。

プラグインとしてインストールするgrunt-contribは、Gruntがメンテナンスしている公式プラグインで、複数のプラグインがひとまとめになっています。

全て使用するケースは少ないとは思いますが、個別にインストールする手間が省けるので今回はこれを使用します。

grunt-contrib-clean ファイルやフォルダを削除する
grunt-contrib-coffee CoffeeScriptをJavaScriptにコンパイルする
grunt-contrib-compass Compassをcssにコンパイルする
grunt-contrib-compress ファイルやフォルダをgzip, tar, tgz, zip圧縮
grunt-contrib-concat 複数のファイルを連結し、1つにまとめる
grunt-contrib-connect ローカルサーバーを起動し接続する
grunt-contrib-copy ファイルやフォルダをコピーする
grunt-contrib-csslint css-lintのルールに従って望ましくないcssの記述をチェックする
grunt-contrib-cssmin 複数のcssファイルの結合・cssの改行、スペースの除去・gzip圧縮
grunt-contrib-handlebars JavaScriptのテンプレート変換エンジンhandlebarsをJavaScriptTemplates(JST)にプリコンパイル?
grunt-contrib-htmlmin html-minifierを使用し、htmlコードをminify
grunt-contrib-imagemin pngとjpgのファイルサイズを小さくする
grunt-contrib-jade node.jsのテンプレートエンジンjadeをhtmlへコンパイル
grunt-contrib-jasmine ヘッドレスブラウザPhantomJSでJavaScriptのテスティングフレームワークJasmineを実行
grunt-contrib-jshint JSHintでJavaScriptコードのエラーや問題になりそうな箇所をチェック
grunt-contrib-jst Underscore.jsのテンプレートをJavaScriptTemplates(JST)にプリコンパイル?
grunt-contrib-less cssプリプロセッサLESSをcssにコンパイル
grunt-contrib-livereload 指定したファイルやフォルダに変更があればブラウザをリロード
grunt-contrib-nodeunit Nodeunitを実行する
grunt-contrib-qunit JavaScriptのテスティングフレームワークQUnitをPhantomJSで実行
grunt-contrib-requirejs RequireJSを使用しているプロジェクトをr.jsで最適化
grunt-contrib-sass Sassをcssにコンパイル
grunt-contrib-stylus Stylusをcssにコンパイル
grunt-contrib-uglify JavaScriptをUglifyJSでminify
grunt-contrib-watch ファイルの変更を監視し、事前に定義されたタスクを実行する
grunt-contrib-yuidoc YUIDocを用いてJavaScriptドキュメントを生成する
以上がgrunt-contribに含まれているプラグインです。必要なものだけを単独でインストールしても構いません。

こちらのページやnpmから探してみて下さい。

便利なプラグイン - Grunt Devtools



ChromeのデベロッパーツールからGUIでGruntのタスクを実行できるプラグイン

  1. Chromeの機能拡張Grunt Devtoolsをインストール
  2. プロジェクトのルートディレクトリでターミナルから
    $ npm install grunt-devtools
  3. Gruntfile.jsに
    grunt.loadNpmTasks('grunt-devtools');
    を追記
  4. ターミナルから
    $ grunt devtools
  5. Chromeのデベロッパーツールをオープン
これでChrome上でタスクを実行したり出来ます。詳細はGitHubページをご確認下さい。

タスクの登録・設定・実行

今回は、開発中に
  • Sassをcssにコンパイル
  • ローカルサーバー起動
  • プロジェクトのファイルを監視し、変更があればブラウザをライブリロード
を実行し、grunt buildというタスクを登録して公開用に
  • cssの圧縮
  • png・jpgの圧縮
を実行してみたいと思います。
まずは適当にInitializrからプロジェクトのひな形をダウンロードし、展開します。

Gruntfile.jsの作成

Gruntを使う上で肝となるGruntfile.jsを作成します。
module.exports = function (grunt) {
grunt.initConfig({
    pkg : grunt.file.readJSON('package.json'),  //package.jsonの情報を読み込み

    /*ここにプラグインの設定を書いていく*/

    }
});

grunt.loadNpmTasks('grunt-contrib');  //プラグインの読み込み

grunt.registerTask('default',['XXXXX']);  //"grunt"コマンドで実行するタスクの登録
};
ひな形としてはこのような形になります。他にも書き方はありますが、今回はこれでやってみます。

1. プラグインの設定

contrib-sassを例に設定の書き方を示します。
contrib-sassはscssで書いたものをcssにコンパイルします。

_sassというフォルダを作成し、scssファイルはその中に入れ、cssフォルダにコンパイルしたものが出力されるようにしてみます。どのプラグインもGitHubページに設定のサンプルがあるので参考にしながら書いていきます。

module.exports = function (grunt) {
grunt.initConfig({
    pkg : grunt.file.readJSON('package.json'),  //package.jsonの情報を読み込み
    //以下がsassの設定
    sass : {
        dev : {                        //devは任意の実行ターゲット名
            options : {                //optionsはSassの設定
                style : 'expanded'
            },
            files   : {                //出力先css : 元のscssフォルダ
                'css/main.css' : ['_sass/*.scss']
            }
        }
    }
    //ここまでsassの設定
});

grunt.loadNpmTasks('grunt-contrib');  //プラグインの読み込み

grunt.registerTask('default',['sass']);  //'default'タスクに実行したいプラグイン名を配列で指定
};
見やすいようにsassの部分だけ抜き出してみます。

sass : {
    dev : {                        //devは任意の実行ターゲット名
        options : {                //optionsはSassの設定
            style : 'expanded'
        },
        files   : {                //出力先css : 元のscssフォルダ
            'css/main.css' : ['_sass/*.scss']
        }
    }
}
devは任意の実行ターゲット名で、ある設定をグループにしたものです。開発時はこちらの設定を使用し、後でdist(distribute/公開用)という設定グループを追加してcssを圧縮したものを出力する設定にしたいと思います。

options : {           //optionsはSassの設定
    style : 'expanded'
}
optionsは、Sass自体の設定で、開発時は見やすいようにexpandedにしています。他にもここにあるオプションが設定できます。

files : {                //出力先css : 元のscssフォルダ
    'css/main.css' : ['_sass/*.scss']
}
filesは、出力先と元のscssファイルを指定しています。単純な例を挙げると

'css/main.css' : '_sass/main.scss'  //出力先css : 元のscss
_sassフォルダのmain.scssをcssフォルダのmain.cssにコンパイルするという意味になります。

実際に指定した形は
'css/main.css' : ['_sass/*.scss']  //出力先css : _sassフォルダ内の.scssの拡張子が付いたファイル
にしています。ワイルドカードを使う場合は、['_sass/*.scss']のように配列の形にしないと意図した出力にならないので注意して下さい。

その他のファイル取得パターン

?  例) ['foo/bar-?.js'] 任意の1文字("/"は含まない)

** 例) ['foo/**/*.js'] サブディレクトリにあるものも含める

{} 例) ['foo/*.{png,jpg,jpeg}'] 複数の条件を指定する(カンマの後にスペースを入れると取得できないので注意)

!  例) ['!foo/*.js'] 指定したもの以外("/"は含まない)

このような指定方法があります。Globbing patterns
他にもテンプレートやフィルターなども使えます。
【参考】Configuring tasks

2. 公開用の設定の追加

今度は公開用のの“dist”という設定グループを追加したいと思います。
module.exports = function (grunt) {
grunt.initConfig({
    pkg  : grunt.file.readJSON('package.json'),
    sass : {
        dev : {
            options : {
                style : 'expanded'
            },
            files   : {
                'css/main.css' : ['_sass/*.scss']
            }
        },
        dist : {                        //公開用のdistグループ
            options : {
                style : 'compressed'    //スペースと改行を取り除き1行にする
            },
            files : {
                'css/main.css' : ['_sass/*.scss']
            }
        }
    }
});

grunt.loadNpmTasks('grunt-contrib');

grunt.registerTask('default', ['sass:dev']); //contrib-sassのdevグループを指定
grunt.registerTask('build', ['sass:dist']);  //contrib-sassのdistグループを指定
};
distの部分で変更したのはoptionsのstyle : compressedの部分だけです。
また、最後の部分で
registerTask('タスク名', ['プラグイン名:グループ名'])
の形に変更しました。これで開発中はターミナルに
$ grunt
で通常のcss出力、作業が終了し公開時には
$ grunt build
で圧縮されたcssが出力されます。

最終的なGruntfile.js

var lrSnippet = require('grunt-contrib/node_modules/grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
grunt.initConfig({
    pkg : grunt.file.readJSON('package.json'),
    watch    : {
        sass       : {
            files : ['_sass/*.scss'],
            tasks : ['sass:dev']
        },
        livereload : {
            files : ['*.html', 'css/.*css', 'js/**/*.js', 'img/*.{png,jpg,jpeg}'],
            tasks : ['livereload']
        }
    },
    sass : {
        dev  : {
            options : {
                style       : 'expanded'
            },
            files   : {
                'css/main.css' : ['_sass/*.scss']
            }
        },
        dist : {
            options : {
                style : 'compressed'
            },
            files   : {
                'css/main.css' : ['_sass/*.scss']
            }
        }
    },
    imagemin : {
        dist : {
            files : [
                {
                    expand : true,
                    cwd    : 'img/',
                    src    : ['*.{png,jpg}'],
                    dest   : 'img/'
                }
            ]
        }
    },
    connect  : {
        options    : {
            port     : 9000,
            hostname : 'localhost'
        },
        livereload : {
            options : {
                middleware : function (connect) {
                    return [
                        lrSnippet,
                        mountFolder(connect, '')
                    ]
                }
            }
        }
    },
    open     : {
        dev : {
            path : 'http://localhost:<%= connect.options.port %>'
        }
    },
});

    grunt.loadNpmTasks('grunt-regarde');
    grunt.loadNpmTasks('grunt-contrib');
    grunt.loadNpmTasks('grunt-open');

    grunt.renameTask('regarde', 'watch');

    grunt.registerTask('default', ['watch']);
    grunt.registerTask('server', ['sass:dev', 'livereload-start', 'connect:livereload', 'open', 'watch']);
    grunt.registerTask('build', ['sass:dist', 'imagemin']);
};
だいぶ端折りましたが、最終的にはこのようになりました。
プラグインの依存の関係でgrunt-regardegrunt-openを追加でインストールしました。
$ grunt server
でローカルサーバーが立ち上がり、ファイルに変更があればブラウザをライブリロードします。
ローカルサーバーを立ち上げる必要がなければ
$ grunt
でファイルの監視のみ
$ grunt build
でcssの圧縮、png・jpgの圧縮を行います。
他にもJavaScriptのユニットテストなど、もっとたくさんのタスクを実行したい場合は、YeomanのGruntfile.jsが参考になります。

まとめ

以前から存在は知っていましたが、初めて使ってみてなかなか楽しいツールだなと思いました。

ただ、導入にあたり色々調べなければならない点、バージョンアップで仕様が変更になりそうな点などが気になります。

参考のためにYeomanも使ってみましたが、ある程度強制される部分はあるけれど導入のしやすさはYeomanのほうが簡単にできました。

【参考サイト】

Web制作で面倒な作業を自動化するビルドツール、Grunt v0.4 入門|Web Design KOJIKA17:

わかりやすく詳しい記事です