귀찮은 일은 다 맡겨라. Grunt Javascript task runner.


특정 디렉토리 안에서 파일이 수정되면 컴파일을 해야 하는 상황이 생겼다.
글자 하나 바꿀 때마다 일일이 그런 수고를 하려니 여간 귀찮은 일이 아니다.
이런 때는 보통 bash 쉘 스크립트를 써 왔는데, os관계없이 어디서나 작동하고, 간편한 녀석을 찾다가 grunt(http://gruntjs.com)를 만나게 되었다. grunt는 프론트엔드 계통에선 꽤 이름을 날리는 녀석으로, 초반 웹 환경 구축을 도와주는 Yeoman(http://yeoman.io)의 한 부분이기도 하다. 요즘엔 grunt와 비슷한 gulp(http://gulpjs.com)이 성능 면에서 우수해서 인기가 좋은데, 여러 작업을 연달아서 할 때 pipe를 이용해서 I/O에 들어가는 시간을 줄이기 때문이란다. 그러나 나는 지금 연속적인 작업에 쓸 것도 아니고, grunt에서도 조만간(?) pipe를 지원할 예정이라고 하니, 커뮤니티가 활성화된 grunt를 쓰기로 했다.

grunt 설치

npm i grunt-cli -g

grunt를 실행할 해당 폴더에서 로컬 모듈 인스톨( 예 : static 폴더에서 실행시 static 폴더에 가서 인스톨)

npm install can-compile --save-dev
npm install grunt-shell --save-dev
npm install grunt-contrib-watch --save-dev
npm install time-grunt --save-dev


grunt 설정파일 예제 - Gruntfile.js

module.exports = function (grunt) {
var static_path = '../static';

// Project configuration.
require('time-grunt')(grunt);
grunt.initConfig({
// pkg: grunt.file.readJSON('./package.json'),

shell: {
scsscompile:{ // scss컴파일은 외부 파이썬 스크립트를 이용해서 한다. 그래서 grunt-shell이 필요하다.
command: 'python2 ../css.py '+static_path,
options: {
stdout: true
}
}
},
cancompile: { // mustache파일을 하나의 자바스크립트 파일로 합쳐주는 모듈
dist: {
src: [static_path+'/views/**/*.mustache'],
out: static_path+'/js/views.build.js',
wrapper: 'define(["can/view/mustache"], function(can) { {{{content}}} });'
}
},
watch: { // grunt watch를 실행하면 해당되는 파일 변경사항이 생길 때 마다 스크립트를 자동으로 실행 한다.
run_mustache: {
files: [static_path+'/views/**/*.mustache'],
tasks: ['cancompile']
},
run_scss: {
files: [static_path+'/scss/**/*.scss'],
tasks: ['shell:scsscompile']
},
options: { nospawn: true, livereload: true } // watch 성능이 향상된다.
}
});

// grunt.registerTask('default', ['watch']); 로 설정하면, 파라미터 없이 grunt를 실행할 때 watch를 실행한다.
grunt.registerTask('watch', ['watch']);
grunt.registerTask('mustache', ['cancompile']);
grunt.registerTask('scss', ['shell:scsscompile']);
grunt.registerTask('static', ['cancompile','shell:scsscompile']);

grunt.loadNpmTasks('can-compile');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-contrib-watch');
};
이 간단한 설정 파일 하나로, 쓸만한 watcher가 만들어졌다. :D
앞으로도 귀찮은 작업을 떠넘길 때 종종 이용해야겠다.

문제 해결


npm이 sudo 권한 없이 설치되지 않을 때

http://stackoverflow.com/questions/16151018/npm-throws-error-without-sudo
sudo chown -R `whoami` ~/.npm
sudo chown -R `whoami` ~/node_modules
sudo chown -R `whoami` /usr/lib/node_modules


Grunt - Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral. 에러가 발생할 때.

http://stackoverflow.com/questions/22285942/grunt-throw-recursive-process-nexttick-detected
grunt.registerTask('sass',['sass']); // 이런식으로 작업 이름과 등록 이름이 같을 때 문제가 발생한다.
grunt.registerTask('styles',['sass']); // 이런식으로 이름을 바꿔준다.

유용한 링크

http://gruntjs.com/
http://gulpjs.com
http://jaysoo.ca/2014/01/27/gruntjs-vs-gulpjs/
http://yeoman.io/blog/performance-optimization.html