gruntで快適JS/CSSビルド生活

hamalog:

grunt というJS/CSSのビルドツールが便利だったので紹介します。(Mac/Linux)

このgruntってのは、JS,CSSを全部まとめて繋げる、まとめてJS lintする、minifyする見たいのをタスクとして登録しておくと、それ実行すればちゃちゃっとやってくれちゃうやつです。さらにwatchっていう機能使えば、ファイルが更新されたらそのタスクをやってくれるみたいなのも。

似たモノで、MakeとかRakeとかCakeとかそういうのがあります。多分、やってる人は前からやってるんですが、最近ちょっとCoffeeScriptをやり始めて、微妙に困ったことがあったので、どーすっぺと探してたら、これが自分にとってソリューションでした。

ここでは、3ステップでCoffeeScriptをコンパイルしてgrowlを出すところまでです。ここで使うサンプルは以下にまとめましたので必要であれば参考にでもすると良いかと思います。

とりあえず、gruntのインストールには、nodeとnpmが必要です。それインストールしたら以下を実行して準備OK。これでgruntコマンドが使える。

npm install -g grunt

step1: jsとcssまとめる。jsはminify

あーいっぱいcssとかjsとかあるけどまとめたい。さらにminifyもして欲しいわーという時。

.
├── common
│   ├── css
│   │   ├── _src # ここにcssのファイルら
│   │   │   ├── style1.css
│   │   │   ├── style2.css
│   │   │   └── style3.css
│   │   └── all.css # まとめたcss
│   └── js
│       ├── _src # ここにjsのファイルら
│       │   ├── script1.js
│       │   ├── script2.js
│       │   └── script3.js
│       ├── all.js     # まとめたjs
│       └── all.min.js # まとめたjsをminifyしたやつ
├── grunt.js # gruntの設定ファイル
└── index.html

上記みたいにディレクトリがあって、grunt.jsにこう書く。

config.init({
  lint: {
    files : [
      'common/js/_src/script1.js',
      'common/js/_src/script2.js',
      'common/js/_src/script3.js'
    ]
  },
  concat:  {
    'common/js/all.js' : [
      'common/js/_src/script1.js',
      'common/js/_src/script2.js',
      'common/js/_src/script3.js'
    ],
    'common/css/all.css' : [
      'common/css/_src/style1.css',
      'common/css/_src/style2.css',
      'common/css/_src/style3.css'
    ]
  },
  watch: {
    files: [
      'common/js/_src/script1.js',
      'common/js/_src/script2.js',
      'common/js/_src/script3.js',
      'common/css/_src/style1.css',
      'common/css/_src/style2.css',
      'common/css/_src/style3.css'
    ],
    tasks: 'lint concat min'
  },
  min: {
    'common/js/all.min.js': [ 'common/js/all.js' ]
  }
});

そして、grunt.jsが置いてあるディレクトリまで行き、

grunt watch

って打てばOK。_srcディレクトリに入れたファイルが更新されたらJS lintしてファイルまとめてminifyしてくれる。all.min.jsとall.cssを読み込んだがコレ

step2: CoffeeScriptコンパイルし、jsとcssまとめる。jsはminify

やりたかったのがコレ。CoffeeScriptには、Cakeというビルドをまとめる方法があるんだけれども、CoffeeScriptまとめた後、他のJSとつなげたりどうのしたりっていうのが、なんか自分で書かないと行けないっぽかった。CoffeeScript使うとは言っても、他にjQueryプラグインだの何だのを使ったりするので、コンパイルしたファイルをまた他のとつなげたりしないといけない。なんかめんどいなーと思ってたら素敵grunt。

さっきのscript1.js、script2.jsをCoffeeScriptにした例。

.
├── common
│   ├── css
│   │   ├── _src
│   │   │   ├── style1.css
│   │   │   ├── style2.css
│   │   │   └── style3.css
│   │   └── all.css
│   └── js
│       ├── _src
│       │   ├── script1.coffee # CoffeeScriptなファイル
│       │   ├── script2.coffee # CoffeeScriptなファイル
│       │   └── script3.js
│       ├── _temp_coffeecompiled.js # コンパイルしたCoffeeScript
│       ├── all.js
│       └── all.min.js
├── grunt.js
└── index.html

grunt.jsの中身はコレ

var proc = require('child_process');

config.init({
  lint: {
    files : [
      'common/js/_src/script3.js'
    ]
  },
  concat:  {
    'common/js/all.js' : [
      'common/js/_temp_coffeecompiled.js',
      'common/js/_src/script3.js'
    ],
    'common/css/all.css' : [
      'common/css/_src/style1.css',
      'common/css/_src/style2.css',
      'common/css/_src/style3.css'
    ]
  },
  watch: {
    files: [
      'common/js/_src/script1.coffee',
      'common/js/_src/script2.coffee',
      'common/js/_src/script3.js',
      'common/css/_src/style1.css',
      'common/css/_src/style2.css',
      'common/css/_src/style3.css'
    ],
    tasks: 'coffee lint concat min'
  },
  min: {
    'common/js/all.min.js': [ 'common/js/all.js' ]
  },
  coffee: {
    'common/js/_temp_coffeecompiled.js': [
      'common/js/_src/script1.coffee',
      'common/js/_src/script2.coffee'
    ]
  }
});

task.registerBasicTask('coffee', 'compile CoffeeScripts', function(data, name) {
  var done = this.async();
  var command = 'coffee -j ' + name + ' -c ' + data.join(' ');
  var out = proc.exec(command, function(err, sout, serr){
    if(err || sout || serr){
      done(false);
    }else{
      done(true);
    }
  });
});

ここでは、coffeeというオレオレタスクをgruntに登録している。そんで、その中では、coffeeプロパティとして登録されたデータを見て、まとめてコンパイルするという流れになってる。そして、watch.tasksにcoffee lint concat minとすれば、さっきと同じ、ファイルが更新されたら、CoffeeScriptをコンパイル、JS lintして、ほかのJSと繋げてall.jsを作り、minify。こんな感じで、複雑なタスクもgruntを使えばかなり手軽に設定できる。(サンプル2)

step3: CoffeeScriptコンパイルし、jsまとめる。終わったらgrowl出す

Mac使ってる人ならほぼほぼ入れていると思われるgrowl。このgrowlは、インストーラに付いてるExtraを入れると、コマンドを打ってgrowlを出すことの出来る機能が追加される。【参考

growlnotify -t "タイトル" -m "メッセージ"

これを、ビルドが終わった時、CoffeeScriptのコンパイルが失敗した時に出す。構成はさっきと同じだけどcss外した。

.
├── common
│   └── js
│       ├── _src
│       │   ├── script1.coffee
│       │   ├── script2.coffee
│       │   └── script3.js
│       ├── _temp_coffeecompiled.js
│       ├── all.js
│       └── all.min.js
├── grunt.js
└── index.html
var proc = require('child_process');

config.init({
  lint: {
    files : [
      'common/js/_src/script3.js'
    ]
  },
  concat:  {
    'common/js/all.js' : [
      'common/js/_temp_coffeecompiled.js',
      'common/js/_src/script3.js'
    ]
  },
  watch: {
    files: [
      'common/js/_src/script1.coffee',
      'common/js/_src/script2.coffee',
      'common/js/_src/script3.js'
    ],
    tasks: 'coffee lint concat min notifyOK'
  },
  min: {
    'common/js/all.min.js': [ 'common/js/all.js' ]
  },
  coffee: {
    'common/js/_temp_coffeecompiled.js': [
      'common/js/_src/script1.coffee',
      'common/js/_src/script2.coffee'
    ]
  }
});

task.registerBasicTask('coffee', 'compile CoffeeScripts', function(data, name) {
  var done = this.async();
  var command = 'coffee -j ' + name + ' -c ' + data.join(' ');
  var out = proc.exec(command, function(err, sout, serr){
    if(err || sout || serr){
      proc.exec("growlnotify -t 'COFFEE COMPILE ERROR!' -m '" + serr + "'");
      done(false);
    }else{
      done(true);
    }
  });
});

task.registerTask('notifyOK', 'done!', function(){
  proc.exec("growlnotify -t 'grunt.js' -m '\(^o^)/'");
});

CoffeeScript書いてる時、エラーあるのが分かりづらいのでコレは便利!(サンプル3)

ほか、ファイルを繋げるときに好きにコメントを入れたりとかもできるので、なんか色々そういうのをやるときは融通が効きそう。ということで、ちょっとしばらく使ってみようと思う。サンプルのgruntファイルなんかもgithubに置いてある。