任務(wù)是Grunt的基本組成。例如你常用的工具:jshint
和nodeunit
。當你每次運行Grunt時,你可以指定它(Grunt)運行一個或者多個任務(wù),通過這些任務(wù)來告訴Grunt你想要它做什么事情。
如果你沒有指定任務(wù),但是定義了一個名為"default"的任務(wù),那么該任務(wù)(default任務(wù))將默認運行(不要驚訝,顧名思義它代表默認會運行哪些定義好的任務(wù))。
如果指定了一個任務(wù)列表,新任務(wù)(名)便是其他一個或多個任務(wù)的別名。每當運行'別名任務(wù)'時,指定在taskList
中的每個任務(wù)(指在grunt.initConfig()
中定義的任務(wù))都會按照指定它們的順序運行。taskList
參數(shù)必須是一個任務(wù)數(shù)組。其語法如下:
grunt.registerTask(taskName, [description, ] taskList);
這里有一個例子,它定義了一個名為'default'別名任務(wù),如果運行Grunt時沒有指定任何任務(wù),它將自動運行'jshint','qunit','concat'和'uglify'任務(wù)。
grunt.registerTask('default', ['jshint','qunit','concat','uglify']);
可以給任務(wù)指定參數(shù)。在下面的例子中,別名任務(wù)'dist'會運行'concat'和'uglify'這兩個任務(wù),并且每個任務(wù)都帶有一個'dist'參數(shù):
grunt.registerTask('dist', ['concat:dist', 'uglify:dist']);
當運行一個多任務(wù)時,Grunt會自動從項目的配置對象中查找同名屬性。多任務(wù)可以有多個配置,并且可以使用任意命名的'targets'。
同時指定像grunt concat:foo
或者grunt concat:bar
這樣的任務(wù)和目標,在運行時Grunt只會處理指定目標的配置;然而如果運行grunt concat
,將會遍歷所有的目標, 并按任務(wù)指定的順序處理每個目標。注意,如果一個任務(wù)已經(jīng)使用grunt.renameTask重命名過,Grunt將會自動在配置對象中查找新任務(wù)名稱屬性。
大部分的contrib任務(wù)(主要是指官方提供的任務(wù)),包括grunt-contrib-jshint插件的jshint任務(wù),以及grunt-contrib-concat插件的concat任務(wù)都是多任務(wù)形式的。
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
(任務(wù)目標會按照指定的順序進行處理)。
grunt.initConfig({
log: {
foo: [1,2,3],
bar: 'hello world',
baz: false
}
});
grunt.registerTask('log','log stuff.', function(){
grunt.log.writeln(this.target + ': ' + this.data);
});
當運行一個基本任務(wù)時,Grunt并不會查找配置和檢查運行環(huán)境--它僅僅運行指定的任務(wù)函數(shù),可以傳遞任意使用冒號分割的參數(shù)作為任務(wù)函數(shù)的參數(shù)(注意多任務(wù)中的冒號并不是傳遞參數(shù),而是指定具體任務(wù)的目標)。
grunt.registerTask(taskName, [description, ] taskFunction);
這里有一個例子演示了如果通過grunt foo:testing:123
運行Grunt將輸出foo, testing 123
。如果運行這個任務(wù)時不傳遞參數(shù),只運行grunt foo
,那么這個任務(wù)會輸出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);
}
});
你可能會著迷于任務(wù)。但是如果你的任務(wù)并沒有遵循多任務(wù)結(jié)構(gòu),那么你可以使用自定義任務(wù)。
grunt.registerTask('default', 'My "default" task description.', function(){
grunt.log.writeln('Currently running the "default" task.');
});
在任務(wù)的內(nèi)部,你還可以運行其他的任務(wù)。
grunt.registerTask('foo', 'My "foo" task.', function() {
//在foo任務(wù)完成之后一次運行隊列中的bar和baz任務(wù)
grunt.task.run('bar', 'baz');
// Or:
grunt.task.run(['bar', 'baz']);
});
任務(wù)還可以是異步的.
grunt.registerTask('asyncfoo', 'My "asyncfoo" task.', function() {
//將任務(wù)轉(zhuǎn)變?yōu)楫惒侥J讲⒔唤odone函數(shù)處理
var done = this.async();
//同步任務(wù)
grunt.log.writeln('Processing task...');
//異步任務(wù)
setTimeout(function() {
grunt.log.writeln('All done!');
done();
}, 1000);
});
任務(wù)也可以訪問它們自身名稱和參數(shù).
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"
如果任務(wù)記錄到錯誤信息,還可以終止任務(wù)執(zhí)行(通過標記任務(wù)失敗的方式)。
grunt.registerTask('foo', 'My "foo" task.', function() {
if (failureOfSomeKind) {
grunt.log.error('This is an error message.');
}
//如果這個任務(wù)拋出錯誤則返回false
if (ifErrors) { return false; }
grunt.log.writeln('This is the success message');
});
當任務(wù)失敗時,所有后續(xù)的除了指定--force
標志的任務(wù)都會終止。
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);
});
任務(wù)還可以依賴于其他任務(wù)的成功執(zhí)行。注意grunt.task.requires
并不會運行其他任務(wù)(比如參數(shù)中指定的任務(wù))。它僅僅檢查那些任務(wù)(其他任務(wù))的運行并沒有失敗(即其他任務(wù),也就是所依賴的任務(wù)是否失敗)。
grunt.registerTask('foo', 'My "foo" task.', function() {
return false;
});
grunt.registerTask('bar', 'My "bar" task.', function() {
//如果foo任務(wù)運行失敗或者沒有運行則任務(wù)失敗
grunt.task.requires('foo');
//如果foo任務(wù)運行成功則執(zhí)行這里的代碼
grunt.log.writeln('Hello, world.');
});
// 用法
// grunt foo bar
// 沒有輸出,因為foo失敗
// grunt bar
// 沒有輸出,因為foo從未運行
如果任務(wù)需要的配置屬性不存在,任務(wù)也可能失敗。
grunt.registerTask('foo', 'My "foo" task', function(){
//如果缺省"meta.name"配置屬性則任務(wù)失敗
grunt.config.requires('meta.name');
//與上一句相同,如果缺省"meta.name"配置屬性則任務(wù)失敗
grunt.config.requires(['meta', 'name']);
//附加記錄
grunt.log.writeln('This will only log if meta.name is defined in the config');
});
任務(wù)還可以訪問配置屬性。
grunt.registerTask('foo', 'My "foo" task.', function(){
// 記錄屬性值,如果屬性未定義則返回null
grunt.log.writeln('The meta.name property is:' + grunt.config('meta.name'));
// 同樣的記錄屬性值,如果屬性未定義則返回null
grunt.log.writeln('The meta.name property is:' + grunt.config(['meta', 'name']));
});
在contrib tasks中可以查看更多的例子。
TODO(從FAQ拉取,推薦process.env)
可能由于你忘記調(diào)用this.async方法來告訴Grunt你的任務(wù)是異步的,那么就可能會發(fā)生這種情況(異步任務(wù)失敗)。為了簡單起見,Grunt使用同步的編碼風(fēng)格,可以在任務(wù)體中通過調(diào)用this.async
將該任務(wù)(調(diào)用這個方法的任務(wù))轉(zhuǎn)換為異步的。
注意傳遞false
給done
函數(shù)就會告訴Grunt任務(wù)已經(jīng)失敗。
例如:
grunt.registerTask('asyncme', 'My asynchronous task.', function(){
var done = this.async();
doSomethingAsync(done);
});