Grunt: Create Tasks in Korean

Grunt은 Javascript Task Runner 입니다.. 이 문서는 Grunt 공식 사이트의 Create tasks를 번역한 문서이며 grunt-cli의 버전이 0.1.11일 때 번역했습니다.

Create tasks

Task는 Grunt의 존재 이유이자 가장 중요한 개념이다. 여러분이 하는 대부분의 일(task)은 jshintnodeunit같은 것들이다. 실행할 Task를 하나 이상 명시해서 Grunt에게 하고 싶은 일이 무엇인지 알려주면, Grunt가 그 일을 매번 실행한다.

여러분이 task를 새로 명시하지 않았고, “default”란 이름의 task가 이미 정의되어 있다면, 기본값으로 그 task가 실행된다.

Alias Tasks

다음처럼 새로운 task에 다른 task 명단을 명시하면, 그 신규 task의 이름은 여러 task들을 대표하는 별명(alias)이 된다. 이런 “alias task”가 실행될 때면, taskList에 명시한 모든 task들이 순서대로 실행된다. 이때 taskList 전달인자는 배열이다.

1
grunt.registerTask(taskName, [description, ] taskList)

다음 예제는 Grunt를 특정 task 지정없이 grunt로 실행할 때 자동으로 “jshint”, “qunit”, “concat”, “uglify” task들을 실행하는 “default”라는 alias task다.

1
grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

Task 전달인자를 다음처럼 지정할 수도 있다. “dist”라는 alias task는 “concat”과 “uglify”에서 “dist” target 들만 실행한다.

1
grunt.registerTask('dist', ['concat:dist', 'uglify:dist']);

Multi Tasks

Multi-task로 만든 task는 실행될 때, Grunt 환경 설정 객체에서 동명의 프로퍼티를 찾는다. 또한 multi-task는 적절한 target(task의 하위 개념) 명으로 각자의 환경설정을 가질 수 있다.

grunt concat란 컴멘드가 그 안의 모든 target를 순회하는 반면에, grunt concat:foogrunt concat:bar처럼 task와 target까지 지정하면, 특정 target의 환경설정만 가져온다. 이때 grunt.task.renameTask로 이름을 변경하면, 바꾼 task 명으로 환경 설정을 찾는다.

grunt-contrib-jshint plugin jshint taskgrunt-contrib-concat plugin concat task같이 contrib로 시작하는 대부분의 task는 multi task다.

1
grunt.registerMultiTask(taskName, [description, ] taskFunction)

다음 multi-task에서 grunt log:foo로 grunt를 실행하면 foo: 1,2,3가 로그로 찍히고, grunt log:bar로 grunt를 실행하면 bar: hello world가 찍힌다. 하지만 grunt log로 grunt를 실행하면 순서대로 foo: 1,2,3가 찍히고 bar: hello world가 찍힌 다음 baz: false가 찍힌다.

1
2
3
4
5
6
7
8
9
10
11
grunt.initConfig({
  log: {
    foo: [1, 2, 3],
    bar: 'hello world',
    baz: false
  }
});

grunt.registerMultiTask('log', 'Log stuff.', function() {
  grunt.log.writeln(this.target + ': ' + this.data);
});

“Basic” Tasks

Multi-task가 아닌 기본 task가 실행될 때는 Grunt가 환경설정을 바라보지 않는다. 지정한 task function만 실행한다. 기본 task에서는 콜론(:)로 구분한 인자 목록을 task function 함수의 전달인자로 넘길 수 있다.

1
grunt.registerTask(taskName, [description, ] taskFunction)

grunt foo:testing:123를 입력하면 foo, testing 123가 콘솔에 출력된다. grunt foo처럼 아무 인자도 넘기지 않고 실행하면 foo, no args가 콘솔에 찍힌다.

1
2
3
4
5
6
7
grunt.registerTask('foo', 'A sample task that logs stuff.', function(arg1, arg2) {
  if (arguments.length === 0) {
    grunt.log.writeln(this.name + ", no args");
  } else {
    grunt.log.writeln(this.name + ", " + arg1 + " " + arg2);
  }
});

Custom tasks

만들려는 Task가 “multi-task” 구조를 따르지 않는다면 기본 task형태로 사용자 정의 task를 만들자.

1
2
3
grunt.registerTask('default', 'My "default" task description.', function() {
  grunt.log.writeln('Currently running the "default" task.');
});

task 안에서 다른 task를 실행할 수 있으며,

1
2
3
4
5
6
grunt.registerTask('foo', 'My "foo" task.', function() {
  // "bar"와 "baz" task가 "foo" 가 끝난 후에 순서대로 실행하려고 대기중이다. 
  grunt.task.run('bar', 'baz');
  // 이렇게 적어도 된다. 
  grunt.task.run(['bar', 'baz']);
});

비동기도 가능하다.

1
2
3
4
5
6
7
8
9
10
11
grunt.registerTask('asyncfoo', 'My "asyncfoo" task.', function() {
  // task를 비동기 모드로 만들고 "done" 함수로 제어한다. 
  var done = this.async();
  // 동기 작업을 실행한다. 
  grunt.log.writeln('Processing task...');
  // 그리고 비동기 작업을 실행한다. 
  setTimeout(function() {
    grunt.log.writeln('All done!');
    done();
  }, 1000);
});

이렇게 만든 task도 그 이름과 인자를 사용해서 접근할 수 있다.

1
2
3
4
5
6
7
8
9
10
grunt.registerTask('foo', 'My "foo" task.', function(a, b) {
  grunt.log.writeln(this.name, a, b);
});

// 사용법:
// grunt foo foo:bar
//   출력로그: "foo", undefined, undefined
//   출력로그: "foo", "bar", undefined
// grunt foo:bar:baz
//   출력로그: "foo", "bar", "baz"

Task에서 에러가 발생하면 Task를 실패처리 할 수도 있다.

1
2
3
4
5
6
7
8
9
10
grunt.registerTask('foo', 'My "foo" task.', function() {
  if (failureOfSomeKind) {
    grunt.log.error('에러 메세지');
  }

  // task 실행 중 에러가 있다면 false를 반환해서 실패 처리한다.
  if (ifErrors) { return false; }

  grunt.log.writeln('성공 메세지');
});

task가 실패하면, --force를 붙이지 않는한 그 이후 작업은 모두 중단된다.

1
2
3
4
5
6
7
8
9
10
11
12
grunt.registerTask('foo', 'My "foo" task.', function() {
  // 동기적 실패 처리
  return false;
});

grunt.registerTask('bar', 'My "bar" task.', function() {
  var done = this.async();
  setTimeout(function() {
    // 비동기적 실패 처리
    done(false);
  }, 1000);
});

Task는 다른 task가 성공적으로 실행되었는지 여부와 관련지을 수도 있다. grunt.task.requires는 실제로 다른 task를 실행하지는 않지만, 그 task가 실행되었는지, 실패는 없었는지를 확인한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
grunt.registerTask('foo', 'My "foo" task.', function() {
  return false;
});

grunt.registerTask('bar', 'My "bar" task.', function() {
  // "foo" task가 실패했거나 실행된적이 없다면, 이 task를 실패 처리한다. 
  grunt.task.requires('foo');
  // 이 코드는 "foo" task가 성공적으로 실행된 적이 있을 때만 실행된다. 
  grunt.log.writeln('Hello, world.');
});

// 사용법
// grunt foo bar
//   foo가 실패하는 task이므로 로그는 출력되지 않는다. 
// grunt bar
//   foo가 실행된적이 없으므로 로그는 출력되지 않는다. 

grunt.config.requires를 사용하면, Task가 존재하지 않는 환경설정 프로퍼티를 요구할 때, 실패 처리할 수 있다.

1
2
3
4
5
6
7
8
grunt.registerTask('foo', 'My "foo" task.', function() {
  // "meta.name" 란 환경설정 프로퍼티가 없으면 이 타스트를 실패 처리한다. 
  grunt.config.requires('meta.name');
  // 이경우도 "meta.name" 환경설정 프로퍼티가 없다면, 실패한다. 
  grunt.config.requires(['meta', 'name']);
  // 조건이 충족되어야 로그가 출력된다. 
  grunt.log.writeln('meta.name이 환경설정에 정의되어있을 때만 로그가 출력된다.');
});

환경설정 프로퍼티에는 grunt.config로 접근할 수 있다.

1
2
3
4
5
6
grunt.registerTask('foo', 'My "foo" task.', function() {
  // 프로퍼티 값을 로그로 출력한다. 프로퍼티가 undefined이면 null을 반환한다. 
  grunt.log.writeln('The meta.name property is: ' + grunt.config('meta.name'));
  // 이경우도 프로퍼티 값을 로그로 출력한다. 프로퍼티가 undefined이면 null을 반환한다. 
  grunt.log.writeln('The meta.name property is: ' + grunt.config(['meta', 'name']));
});

더 자세한 예제는 contrib task들을 참고하자.

CLI optiosn / environment

내용 없음.

Why doesn’t my asynchronous task complete?

비동기 task를 짰는데 완료되지 않는다면, 대부분 this.asynce를 호출하지 않았기 때문이다. 쉽게 하려면, 동기식 코딩 스타일을 사용하고 나서 task 내부에 this.async()를 호출해서 비동기로 변경할 수 있다.

그리고 다시 말하지만, done()에 인자로 false를 넘기면 Grunt에게 task가 실패했다고 알릴 수 있다.

예제 코드다.

1
2
3
4
grunt.registerTask('asyncme', 'My asynchronous task.', function() {
  var done = this.async();
  doSomethingAsync(done);
});

Comments