這個指南解釋了如何使用 Gruntfile 來為你的項目配置task。如果你還不知道 Gruntfile 是什么,請先閱讀 快速入門 指南并看看這個 Gruntfile 實例。
Grunt的task配置都是在 Gruntfile 中的grunt.initConfig方法中指定的。此配置主要是以任務(wù)名稱命名的屬性,也可以包含其他任意數(shù)據(jù)。一旦這些代表任意數(shù)據(jù)的屬性與任務(wù)所需要的屬性相沖突,就將被忽略。
此外,由于這本身就是JavaScript,因此你不僅限于使用JSON;你可以在這里使用任何有效的JavaScript。必要的情況下,你甚至可以以編程的方式生成配置。
grunt.initConfig({ concat: { // 這里是concat任務(wù)的配置信息。 }, uglify: { // 這里是uglify任務(wù)的配置信息 }, // 任意數(shù)據(jù)。 my_property: 'whatever', my_src_files: ['foo/*.js', 'bar/*.js'], });
當運行一個任務(wù)時,Grunt會自動查找配置對象中的同名屬性。多任務(wù)(multi-task)可以通過任意命名的“目標(target)”來定義多個配置。在下面的案例中,concat任務(wù)有名為foo和bar兩個目標,而uglify任務(wù)僅僅只有一個名為bar目標。
grunt.initConfig({ concat: { foo: { // concat task "foo" target options and files go here. }, bar: { // concat task "bar" target options and files go here. }, }, uglify: { bar: { // uglify task "bar" target options and files go here. }, }, });
同時指定任務(wù)(task)和目標(target),例如grunt concat:foo或者grunt concat:bar,將只會處理指定目標(target)的配置,而運行g(shù)runt concat將遍歷所有目標(target)并依次處理。注意,如果一個任務(wù)使用grunt.task.renameTask重命名過,Grunt將在配置對象中查找以新的任務(wù)名命名的屬性。
在一個任務(wù)配置中,options屬性可以用來指定覆蓋內(nèi)置屬性的默認值。此外,每一個目標(target)中還可以擁有一個專門針對此目標(target)的options屬性。目標(target)級的平options將會覆蓋任務(wù)級的options。
options對象是可選的,如果不需要,可以忽略。
grunt.initConfig({ concat: { options: { // 這里是任務(wù)級的Options,覆蓋默認值 }, foo: { options: { // "foo" target options may go here, overriding task-level options. }, }, bar: { // No options specified; this target will use task-level options. }, }, });
由于大多的任務(wù)都是執(zhí)行文件操作,Grunt有一個強大的抽象層用于聲明任務(wù)應(yīng)該操作哪些文件。這里有好幾種定義src-dest(源文件-目標文件)文件映射的方式,均提供了不同程度的描述和控制操作方式。任何一種多任務(wù)(multi-task)都能理解下面的格式,所以你只需要選擇滿足你需求的格式就行。
所有的文件格式都支持src和dest屬性,此外"Compact"[簡潔]和"Files Array"[文件數(shù)組]格式還支持以下一些額外的屬性:
這種形式允許每個目標對應(yīng)一個src-dest文件映射。通常情況下它用于只讀任務(wù),比如grunt-contrib-jshint,它就只需要一個單一的src屬性,而不需要關(guān)聯(lián)的dest選項. 這種格式還支給每個src-dest文件映射指定額外的屬性。
grunt.initConfig({ jshint: { foo: { src: ['src/aa.js', 'src/aaa.js'] }, }, concat: { bar: { src: ['src/bb.js', 'src/bbb.js'], dest: 'dest/b.js', }, }, });
這種形式支持每個目標對應(yīng)多個src-dest形式的文件映射,屬性名就是目標文件,源文件就是它的值(源文件列表則使用數(shù)組格式聲明)??梢允褂眠@種方式指定數(shù)個src-dest文件映射, 但是不能夠給每個映射指定附加的屬性。
grunt.initConfig({ concat: { foo: { files: { 'dest/a.js': ['src/aa.js', 'src/aaa.js'], 'dest/a1.js': ['src/aa1.js', 'src/aaa1.js'], }, }, bar: { files: { 'dest/b.js': ['src/bb.js', 'src/bbb.js'], 'dest/b1.js': ['src/bb1.js', 'src/bbb1.js'], }, }, }, });
這種形式支持每個目標對應(yīng)多個src-dest文件映射,同時也允許每個映射擁有額外屬性:
grunt.initConfig({ concat: { foo: { files: [ {src: ['src/aa.js', 'src/aaa.js'], dest: 'dest/a.js'}, {src: ['src/aa1.js', 'src/aaa1.js'], dest: 'dest/a1.js'}, ], }, bar: { files: [ {src: ['src/bb.js', 'src/bbb.js'], dest: 'dest/b/', nonull: true}, {src: ['src/bb1.js', 'src/bbb1.js'], dest: 'dest/b1/', filter: 'isFile'}, ], }, }, });
dest-as-target文件格式在多任務(wù)和目標出現(xiàn)之前是一個過渡形式,目標文件路徑實際上就是目標名稱。遺憾的是, 由于目標名稱是文件路徑,那么運行g(shù)runt task:target可能不合適。此外,你也不能指定一個目標級的options或者給每個src-dest文件映射指定額外屬性。
此種格式已經(jīng)不贊成使用,請盡量不要使用。
grunt.initConfig({ concat: { 'dest/a.js': ['src/aa.js', 'src/aaa.js'], 'dest/b.js': ['src/bb.js', 'src/bbb.js'], }, });
filter屬性可以給你的目標文件提供一個更高級的詳細幫助信息。只需要使用一個有效的fs.Stats 方法名。下面的配置僅僅清理一個與模式匹配的真實的文件:
grunt.initConfig({ clean: { foo: { src: ['tmp/**/*'], filter: 'isFile', }, }, });
或者創(chuàng)建你自己的filter函數(shù),根據(jù)文件是否匹配來返回true或者false。下面的例子將僅僅清理一個空目錄:
grunt.initConfig({ clean: { foo: { src: ['tmp/**/*'], filter: function(filepath) { return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0); }, }, }, });
通常分別指定所有源文件路徑是不切實際的,因此Grunt通過內(nèi)置支持node-glob 和 minimatch 庫來匹配文件名(又叫作globbing)。
然這并不是一個綜合的匹配模式方面的教程,你只需要知道如何在文件路徑匹配過程中使用它們即可:
每個人都需要知道的是:foo/*.js將匹配位于foo/目錄下的所有的.js結(jié)尾的文件;而foo/**/*js將匹配foo/目錄以及其子目錄中所有以.js結(jié)尾的文件。
此外, 為了簡化原本復(fù)雜的通配符模式,Grunt允許指定一個數(shù)組形式的文件路徑或者一個通配符模式。所有模式按順序處理,模式處理的過程中,帶有!前綴的模式所匹配的文件將不包含在結(jié)果集中。 而且其結(jié)果集中的每一項也是唯一的。
例如:
// 指定單個文件: {src: 'foo/this.js', dest: ...} // 指定一個文件數(shù)組: {src: ['foo/this.js', 'foo/that.js', 'foo/the-other.js'], dest: ...} // 使用一個匹配模式: {src: 'foo/th*.js', dest: ...} // 一個獨立的node-glob模式: {src: 'foo/{a,b}*.js', dest: ...} // 也可以這樣編寫: {src: ['foo/a*.js', 'foo/b*.js'], dest: ...} // foo目錄中所有的.js文件,按字母順序排序: {src: ['foo/*.js'], dest: ...} // 首先是bar.js,接著是剩下的.js文件,并按字母順序排序: {src: ['foo/bar.js', 'foo/*.js'], dest: ...} // 除bar.js之外的所有的.js文件,按字母順序排序: {src: ['foo/*.js', '!foo/bar.js'], dest: ...} // 按字母順序排序的所有.js文件,但是bar.js在最后。 {src: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], dest: ...} // 模板也可以用于文件路徑或者匹配模式中: {src: ['src/<%= basename %>.js'], dest: 'build/<%= basename %>.min.js'} // 它們也可以引用在配置中定義的其他文件列表: {src: ['foo/*.js', '<%= jshint.all.src %>'], dest: ...}
更多關(guān)于通配符模式的語法,請查看node-glob 和 minimatch 的文檔。
當你希望處理大量的單個文件時,這里有一些附加的屬性可以用來動態(tài)的構(gòu)建一個文件列表。這些屬性都可以用于Compact和Files Array文件映射格式。
expand 設(shè)置為true用于啟用下面的選項:
在下面的例子中,uglify 任務(wù)中的static_mappings和dynamic_mappings兩個目標具有相同的src-dest文件映射列表, 這是因為任務(wù)運行時Grunt會自動展開dynamic_mappings文件對象為4個單獨的靜態(tài)src-dest文件映射--假設(shè)這4個文件能夠找到。
可以指定任意靜態(tài)src-dest和動態(tài)的src-dest文件映射相互結(jié)合。
grunt.initConfig({ uglify: { static_mappings: { // Because these src-dest file mappings are manually specified, every // time a new file is added or removed, the Gruntfile has to be updated. files: [ {src: 'lib/a.js', dest: 'build/a.min.js'}, {src: 'lib/b.js', dest: 'build/b.min.js'}, {src: 'lib/subdir/c.js', dest: 'build/subdir/c.min.js'}, {src: 'lib/subdir/d.js', dest: 'build/subdir/d.min.js'}, ], }, dynamic_mappings: { // Grunt will search for "**/*.js" under "lib/" when the "uglify" task // runs and build the appropriate src-dest file mappings then, so you // don't need to update the Gruntfile when files are added or removed. files: [ { expand: true, // Enable dynamic expansion. cwd: 'lib/', // Src matches are relative to this path. src: ['**/*.js'], // Actual pattern(s) to match. dest: 'build/', // Destination path prefix. ext: '.min.js', // Dest filepaths will have this extension. extDot: 'first' // Extensions in filenames begin after the first dot }, ], }, }, });
使用<% %>分隔符指定的模板會在任務(wù)從它們的配置中讀取相應(yīng)的數(shù)據(jù)時將自動擴展掃描。模板會被遞歸的展開,直到配置中不再存在遺留的模板相關(guān)的信息(與模板匹配的)。
整個配置對象決定了屬性上下文(模板中的屬性)。此外,在模板中使用grunt以及它的方法都是有效的,例如: <%= grunt.template.today('yyyy-mm-dd') %>。
下面以concat任務(wù)配置為例,運行g(shù)runt concat:sample時將通過banner中的/* abcde */連同foo/*.js+bar/*.js+bar/*.js匹配的所有文件來生成一個名為build/abcde.js的文件。
grunt.initConfig({ concat: { sample: { options: { banner: '/* <%= baz %> */\n', // '/* abcde */\n' }, src: ['<%= qux %>', 'baz/*.js'], // [['foo/*.js', 'bar/*.js'], 'baz/*.js'] dest: 'build/<%= baz %>.js', // 'build/abcde.js' }, }, //用于任務(wù)配置模板的任意屬性 foo: 'c', bar: 'b<%= foo %>d', // 'bcd' baz: 'a<%= bar %>e', // 'abcde' qux: ['foo/*.js', 'bar/*.js'], });
在下面的Gruntfile中,項目的元數(shù)據(jù)是從package.json文件中導(dǎo)入到Grunt配置中的,并且grunt-contrib-uglify 插件中的 uglify 任務(wù)被配置用于壓縮一個源文件以及使用該元數(shù)據(jù)動態(tài)的生成一個banner注釋。
Grunt有g(shù)runt.file.readJSON和grunt.file.readYAML兩個方法分別用于引入JSON和YAML數(shù)據(jù)。
grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' }, dist: { src: 'src/<%= pkg.name %>.js', dest: 'dist/<%= pkg.name %>.min.js' } } });
更多建議: