# 創建任務
任務是Grunt的面包和奶油。就像你常用的工具,如:?`jshint`?或?`nodeunit`。每當運行Grunt時, 你可以為其指定一個或多個任務, 這些任務用于告訴Grunt你想要它做什么事情。
如果你沒有指定一個任務,并且你已經定義一個名為 "default" 的任務,那么該任務將會默認被執行(不用詫異,總要做點兒什么啊!)。
## 任務別名
如果指定了一個任務列表,新任務將是這一個或多個指定任務的別名。當運行此 "任務別名" 時,在`taskList`?中指定的每個任務都會按照其出現的順序依次執行。`taskList`參數必須時一個任務數組。
~~~
grunt.registerTask(taskName, [description, ] taskList)
~~~
下面的任務別名案例中定義了一個 'default' 任務,如果運行Grunt時沒有指定任何任務,它將自動執行'jshint'、'qunit'、'concat' 和 'uglify' 任務。
~~~
grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);
~~~
還可以給任務指定參數。在下面的案例中,別名 "dist" 將執行 "concat" 和 "uglify" 兩個任務,并且它們都帶有一個 "dist" 參數:
~~~
grunt.registerTask('dist', ['concat:dist', 'uglify:dist']);
~~~
## 多任務
當運行一個多任務時,Grunt會自動從項目的配置對象中查找同名屬性。多任務可以有多個配置,并且可以使用任意命名的'targets'。
同時指定像`grunt concat:foo`或者`grunt concat:bar`這樣的任務和目標,在運行時Grunt只會處理指定目標的配置;然而如果運行`grunt concat`,將會遍歷所有的目標, 并按任務指定的順序處理每個目標。注意,如果一個任務已經使用[grunt.task.renameTask](http://www.gruntjs.net/grunt.task#grunt.task.renametask)重命名過,Grunt將會自動在配置對象中查找新任務名稱屬性。
大部分的contrib任務(主要是指官方提供的任務),包括[grunt-contrib-jshint插件的jshint任務](https://github.com/gruntjs/grunt-contrib-jshint#jshint-task),以及[grunt-contrib-concat插件的concat任務](https://github.com/gruntjs/grunt-contrib-concat#concat-task)都是多任務形式的。
~~~
grunt.registerMultiTask(taskName, [description, ] taskFunction)
~~~
對于指定的配置,這里有一個案例演示了如果通過`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`(任務目標會按照指定的順序進行處理)。
~~~
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);
});
~~~
## "基本" 任務
當一個基本任務執行時,Grunt并不會檢查配置和環境 -- 它僅僅執行指定的任務函數,并傳遞任何使用冒號分割的參數作為函數的參數。
~~~
grunt.registerTask(taskName, [description, ] taskFunction)
~~~
下面的案例中,如果執行?`grunt foo:testing:123`,將輸出日志?`foo, testing 123`。 如果執行這個任務時不傳遞參數,只是執行?`grunt foo`,那么將輸出日志?`foo, no args`。
~~~
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);
}
});
~~~
## 自定義任務
你可以和任務一起瘋狂。如果你的任務并沒有遵循 "多任務" 結構,那就使用自定義任務。
~~~
grunt.registerTask('default', 'My "default" task description.', function() {
grunt.log.writeln('Currently running the "default" task.');
});
~~~
在一個任務內部,你可以執行其他的任務。
~~~
grunt.registerTask('foo', 'My "foo" task.', function() {
// Enqueue "bar" and "baz" tasks, to run after "foo" finishes, in-order.
grunt.task.run('bar', 'baz');
// Or:
grunt.task.run(['bar', 'baz']);
});
~~~
任務也可以是異步的。
~~~
grunt.registerTask('asyncfoo', 'My "asyncfoo" task.', function() {
// Force task into async mode and grab a handle to the "done" function.
var done = this.async();
// Run some sync stuff.
grunt.log.writeln('Processing task...');
// And some async stuff.
setTimeout(function() {
grunt.log.writeln('All done!');
done();
}, 1000);
});
~~~
任務也可以訪問它們自身名稱和參數。
~~~
grunt.registerTask('foo', 'My "foo" task.', function(a, b) {
grunt.log.writeln(this.name, a, b);
});
// 用法:
// grunt foo foo:bar
// logs: "foo", undefined, undefined
// logs: "foo", "bar", undefined
// grunt foo:bar:baz
// logs: "foo", "bar", "baz"
~~~
如果記錄到任何錯誤,那么任務就會失敗。
~~~
grunt.registerTask('foo', 'My "foo" task.', function() {
if (failureOfSomeKind) {
grunt.log.error('This is an error message.');
}
// 如果這個任務出現錯誤則返回false
if (ifErrors) { return false; }
grunt.log.writeln('This is the success message');
});
~~~
當任務失敗時,所有后續任務都將終止,除非指定?`--force`?。
~~~
grunt.registerTask('foo', 'My "foo" task.', function() {
// Fail synchronously.
return false;
});
grunt.registerTask('bar', 'My "bar" task.', function() {
var done = this.async();
setTimeout(function() {
// Fail asynchronously.
done(false);
}, 1000);
});
~~~
任務還可以依賴于其他任務的成功執行。注意?`grunt.task.requires`?并不會真正的運行其他任務,它僅僅檢查其它任務是否已經執行,并且沒有失敗。
~~~
grunt.registerTask('foo', 'My "foo" task.', function() {
return false;
});
grunt.registerTask('bar', 'My "bar" task.', function() {
// 如果"foo"任務運行失敗或者沒有運行則任務失敗。
grunt.task.requires('foo');
// 如果"foo"任務運行成功則執行這里的代碼。
grunt.log.writeln('Hello, world.');
});
// 用法:
// grunt foo bar
// 沒有輸出,因為"foo"失敗。
// grunt bar
// 沒有輸出,因為"foo"從未運行。
~~~
如果任務需要的配置屬性不存在,其也可能失敗。
~~~
grunt.registerTask('foo', 'My "foo" task.', function() {
// Fail task if "meta.name" config prop is missing
// Format 1: String
grunt.config.requires('meta.name');
// or Format 2: Array
grunt.config.requires(['meta', 'name']);
// Log... conditionally.
grunt.log.writeln('This will only log if meta.name is defined in the config.');
});
~~~
任務還可以訪問配置屬性。
~~~
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 tasks](https://github.com/gruntjs/)?中可以查看更多案例。
## CLI 參數 / 環境
通過?`process.env`?來訪問[環境變量](http://en.wikipedia.org/wiki/Environment_variable)。
請參考?[使用命令行工具](http://using-the-cli/)章節,查看完整的的命令行選項列表。
## 為什么我的異步task沒有完成?
如果發生這種情況,可能是由于你忘記調用?[this.async](http://www.gruntjs.net/inside-tasks#this.async)?方法來告訴Grunt你的任務是異步的。為了簡單起見,Grunt使用同步的編碼風格,可以在task體中通過調用?`this.async()`?將其轉換為異步的。
注意,傳遞?`false`?給?`done()`?函數就會告訴Grunt你的任務已經失敗。
例如:
~~~
grunt.registerTask('asyncme', 'My asynchronous task.', function() {
var done = this.async();
doSomethingAsync(done);
});
~~~
## 額外參考資料
如果你需要更多參考資料來創建自己的 task ,請參考?[API](http://www.gruntjs.net/api)?文檔 if you need extra reference to create your tasks.