最近ようやくcoffeescriptにもLESSにも慣れてきました。で、そろそろgruntを活用しようかなと先月くらいから使ってみてますが便利です。
- *.less →(コンパイル)→ style.css →(圧縮)→
style.min.css
- *.coffee →(コンパイル)→ *.js →(連結)→ app.js →(圧縮)→
app.min.js
- *-test.coffee →(コンパイル)→ *-test.js →(連結)→
tests.js
app.min.js
,tests.js
を読み込んでqunitでテスト- index.htmlでは
app.min.js
とstyle.min.css
を読み込む
こんなかんじの事を簡単にできます。テストもcoffeescriptで書けて良いです。
現在リリースされている grunt v0.3.9 では coffee, less, sqwishに対応したタスクが無いので、カスタムタスクを grunt.js 内で登録して使用してます(pluginとして環境に登録はしていない)。
- $ grunt watch &
- lessやcoffeeファイルの編集を監視して、自動的にコンパイルして連結して圧縮してくれます。
- $ grunt clean
- 出力ファイルやフォルダを全て削除します。
- $ grunt
- lessやcoffeeファイルをコンパイルして連結して圧縮して、圧縮したjsを使ってqunitでテストしてくれます。
フォルダ構成
私の場合はほぼ全てのプロジェクトがGoogle App Engine/Javaプロジェクトで、mavenを使っているのでフォルダ構成は次のような状況です。
- src/main/coffee
- プロダクト用の coffee ファイル
- src/main/less
- less ファイル
- src/test/coffee
- テスト用の coffee ファイル
- src/test/qunit
- qunit.css, qunit.js, sinon.js, qunit.html(war/js/app.min.js, target/tests.js)
出力先となるフォルダ・ファイル。
- target/js
- プロダクト用の coffee ファイルをコンパイルしたJavaScriptファイル
- target/js.test
- テスト用の coffee ファイルをコンパイルしたJavaScriptファイル
- target/tests.js
- テスト用のcoffee ファイルをコンパイルしたJavaScriptファイルを連結したJavaScriptファイル
- war/css/style.css
- lessをコンパイルしたcssファイル
- war/css/style.min.css
- lessをコンパイルしたcssファイルを圧縮したファイル
- war/js/app.js
- プロダクト用のcoffeeファイルをコンパイルしたJavaScriptファイルを連結したJavaScriptファイル
- war/js/app.min.js
- プロダクト用のcoffeeファイルをコンパイルしたJavaScriptファイルを連結したJavaScriptファイルを圧縮したJavaScriptファイル
grunt.js
次がgruntの定義ですが、これを利用するには、nodejs, npm, phantomjs が必要で、npmでは grunt, less, coffee-script, sqwish をインストールしておく必要があります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = function (grunt) { | |
grunt.initConfig({ | |
clean:{ | |
js:{ | |
files:[ | |
'<config:concat.src.dest>', | |
'<config:concat.tests.dest>', | |
'<config:min.dist.dest>' | |
], | |
dirs:[ | |
'<config:coffee.src.dest>', | |
'<config:coffee.tests.dest>' | |
] | |
}, | |
css: { | |
files: [ | |
'<config:less.dist.dest>', | |
'<config:sqwish.dist.dest>' | |
] | |
} | |
}, | |
less:{ | |
dist:{ | |
src:'src/main/less/customized.less', dest:'war/css/style.css' | |
} | |
}, | |
sqwish:{ | |
dist:{ | |
src:'<config:less.dist.dest>', dest:'war/css/style.min.css' | |
} | |
}, | |
coffee:{ | |
src:{ | |
dir:'src/main/coffee/', dest:'target/js/' | |
}, | |
tests:{ | |
dir:'src/test/coffee/', dest:'target/js.test/' | |
} | |
}, | |
concat:{ | |
src:{ | |
src:[ // coffeeファイルを追加する場合はここにも追加する。 | |
'target/js/lib1.js', | |
'target/js/lib2.js', | |
'target/js/main.js' | |
], | |
dest:'war/js/app.js' | |
}, | |
tests:{ | |
src:'target/js.test/*.js', dest:'target/tests.js' | |
} | |
}, | |
min:{ | |
dist:{ | |
src:'<config:concat.src.dest>', dest:'war/js/app.min.js' | |
} | |
}, | |
qunit:{ | |
files:'src/test/qunit/*.html' | |
}, | |
watch:{ | |
coffee:{ | |
files:['src/main/coffee/**/*.coffee', 'src/test/coffee/**/*.coffee', 'src/main/less/**/*.less'], | |
tasks:'coffee concat min' | |
}, | |
less:{ | |
files:['src/main/less/**/*.less'], | |
tasks:'less sqwish' | |
} | |
} | |
}); | |
// Default task. | |
grunt.registerTask('default', 'coffee concat min less sqwish qunit'); | |
// | |
// register custom tasks and helpers. | |
// | |
var log = grunt.log; | |
var exec = require('child_process').exec; | |
grunt.registerHelper('exec', function (opts, done) { | |
var command = opts.cmd + ' ' + opts.args.join(' '); | |
exec(command, opts.opts, function (code, stdout, stderr) { | |
if (!done) return; | |
if (code === 0) { | |
done(null, stdout, code); | |
} else { | |
done(code, stderr, code); | |
} | |
}); | |
}); | |
var handleResult = function handleResult(err, stdout, code, done) { | |
if (err) { | |
log.writeln(stdout); | |
done(false); | |
} else { | |
done(true); | |
} | |
}; | |
// task: coffee | |
(function (grunt) { | |
grunt.registerHelper('coffeec', function (fromdir, dest, done) { | |
var args = { cmd:'coffee', args:[ '--compile', '--output', dest, fromdir ] }; | |
grunt.helper('exec', args, function (err, stdout, code) { | |
handleResult(err, stdout, code, done); | |
}); | |
}); | |
grunt.registerMultiTask('coffee', 'compile CoffeeScript', function () { | |
grunt.helper('coffeec', this.data.dir, this.data.dest, this.async()); | |
}); | |
}(grunt)); | |
// task: less. | |
(function (grunt) { | |
grunt.registerHelper('lessc', function (from, dest, done) { | |
var args = { cmd:'lessc', args:[ '--compress', from, dest] }; | |
grunt.helper('exec', args, function (err, stdout, code) { | |
handleResult(err, stdout, code, done); | |
}); | |
}); | |
grunt.registerMultiTask('less', 'compile less', function () { | |
grunt.helper('lessc', this.data.src, this.data.dest, this.async()); | |
}); | |
}(grunt)); | |
// task: sqwish | |
(function (grunt) { | |
grunt.registerHelper('sqwishc', function (from, dest, done) { | |
var args = { cmd:'sqwish', args:[ from, '--output', dest] }; | |
grunt.helper('exec', args, function (err, stdout, code) { | |
handleResult(err, stdout, code, done); | |
}); | |
}); | |
grunt.registerMultiTask('sqwish', 'minify css', function () { | |
grunt.helper('sqwishc', this.data.src, this.data.dest, this.async()); | |
}); | |
}(grunt)); | |
// task: clean | |
(function (grunt) { | |
grunt.registerHelper('rm', function (targets, done) { | |
for (i in targets) { | |
var target = targets[i]; | |
var args = { cmd:'rm -f', args:[ target ] }; | |
grunt.helper('exec', args, function (err, stdout, code) { | |
handleResult(err, stdout, code, done); | |
}); | |
} | |
}); | |
grunt.registerHelper('rd', function (targets, done) { | |
for (i in targets) { | |
var target = targets[i]; | |
var args = { cmd:'rm -rf', args:[ target ] }; | |
grunt.helper('exec', args, function (err, stdout, code) { | |
handleResult(err, stdout, code, done); | |
}); | |
} | |
}); | |
grunt.registerMultiTask('clean', 'compile less', function () { | |
if (this.data.files) { | |
grunt.helper('rm', this.data.files, this.async()); | |
} | |
if (this.data.dirs) { | |
grunt.helper('rd', this.data.dirs, this.async()); | |
} | |
}); | |
}(grunt)); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="utf-8"/> | |
<title>Tests</title> | |
<link rel="stylesheet" href="qunit.css"/> | |
</head> | |
<body> | |
<div id="qunit"></div> | |
<script src="qunit.js"></script> | |
<script src="sinon-1.3.4.js"></script> | |
<!-- ライブラリを追加する場合はここにも追加する --> | |
<script src="../../../war/js/jquery-1.7.2.min.js"></script> | |
<script src="../../../war/js/jquery.ba-hashchange.min.js"></script> | |
<script src="../../../war/js/app.min.js"></script> | |
<script src="../../../target/tests.js"></script> | |
<script> | |
</script> | |
</body> | |
</html> |
0 件のコメント:
コメントを投稿