Grunt 入门教程二:配置任务

2.1 Grunt 配置

任务配置都定义在GruntFile 文件中的 grunt.initConfig 方法中。这个配置一般都是一些以任务名命名的属性,但是也可以包含任意的数据。如果一个属性没有被任何任务用到,就会被忽略。

而且,因为这是 JavaScript 文件,任何合法的 JS 代码都可以写,而不是仅仅局限于 JSON。如果有必要,你甚至可以用代码动态生成配置。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   concat: {  
  3.     // concat task configuration goes here.  
  4.   },  
  5.   uglify: {  
  6.     // uglify task configuration goes here.  
  7.   },  
  8.   // Arbitrary non-task-specific properties.  
  9.   my_property: 'whatever',  
  10.   my_src_files: ['foo/*.js''bar/*.js'],  
  11. });  


2.2 任务配置和任务目标

当一个任务运行时,Grunt 会自动寻找配置中的同名属性。可以通过自定义的“targets”属性来配置多个任务。在下面这个例子中,concat 任务有 foo 和 bar 两个目标,而 uglify 只有一个 bar 目标。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   concat: {  
  3.     foo: {  
  4.       // concat task "foo" target options and files go here.  
  5.     },  
  6.     bar: {  
  7.       // concat task "bar" target options and files go here.  
  8.     },  
  9.   },  
  10.   uglify: {  
  11.     bar: {  
  12.       // uglify task "bar" target options and files go here.  
  13.     },  
  14.   },  
  15. });  


指 定任务名和目标名,比如 grunt concat:foo 或者 grunt concat:bar 只运行目标名指定的配置;如果直接运行 grunt concat 则会顺序执行所有的目标。注意,如果一个任务被 grunt.renameTask 重命名了,Grunt 会在config对象中寻找新的名字命名的属性。

2.3 默认配置

在一个任务配置里,可以通过 options 属性来覆盖默认配置。任务中的每一个目标也都可以有一个与之对应的 options 属性。目标中的options配置会覆盖任务中的options。

options属性是可选的,如果没有必要可以省略。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   concat: {  
  3.     options: {  
  4.       // Task-level options may go here, overriding task defaults.  
  5.     },  
  6.     foo: {  
  7.       options: {  
  8.         // "foo" target options may go here, overriding task-level options.  
  9.       },  
  10.     },  
  11.     bar: {  
  12.       // No options specified; this target will use task-level options.  
  13.     },  
  14.   },  
  15. });  


2.4 文件

因为大部分的任务都是执行文件操作,所以Grunt对所要操作的文件有很强的抽象。有几种方式可以实现源文件到目标文件的映射,可以有多级的冗余和控制(不太好翻译)。任何一种多任务都可以理解下面的这些格式,所以你可以使用任何最合适的格式。

所有的文件的格式都支持”src“和”dest“,但是”简洁“和”文件数组“两种格式还支持如下一些附加属性

  • filter:过滤器,任意一个合法的 fs.stats 方法名(http://nodejs.org/docs/latest/api/fs.html#fs_class_fs_stats),或者任何一个接受 src 作为文件路径并返回 True 或者 False的方法都可以。
  • nonull:非空,如果没有任何一个匹配被找到,那么就返回一个包含这个模式本身的列表。否则,返回一个空列表。这个选项可以结合grunt的 --verbose 参数来帮助调试文件路径问题。
  • dot:可以让模式匹配一个以句点开头的文件名,即使模式没有显式地指定一个句点。
  • matchBase:只匹配base路径,如果设置了这个参数,那么不会匹配子目录。比如 a?b 会匹配 /xyz/123/acb 但是不会匹配 /xyz/acb/123。
  • expand:拓展,执行一个动态的 源文件到目标文件的映射,参见“Building the files object dynamically”。
  • 其他所有的参数都会被当做配置参数传给底层库,参见 node-glob (https://github.com/isaacs/node-glob) 和 minimatch(https://github.com/isaacs/minimatch).

2.5 简洁格式

这种模式一般用在只读任务中,只需要一个 src 属性而不需要 dest属性。简洁格式 也支持附加属性。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   jshint: {  
  3.     foo: {  
  4.       src: ['src/aa.js''src/aaa.js']  
  5.     },  
  6.   },  
  7.   concat: {  
  8.     bar: {  
  9.       src: ['src/bb.js''src/bbb.js'],  
  10.       dest: 'dest/b.js',  
  11.     },  
  12.   },  
  13. });  


2.6 文件对象格式

这种格式可以在一个目标中配置多个 源文件到目标文件的映射。属性名是目标文件,属性值是源文件。对每个目标文件可以定义任意数量的源文件,但是不支持附加属性

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   concat: {  
  3.     foo: {  
  4.       files: {  
  5.         'dest/a.js': ['src/aa.js''src/aaa.js'],  
  6.         'dest/a1.js': ['src/aa1.js''src/aaa1.js'],  
  7.       },  
  8.     },  
  9.     bar: {  
  10.       files: {  
  11.         'dest/b.js': ['src/bb.js''src/bbb.js'],  
  12.         'dest/b1.js': ['src/bb1.js''src/bbb1.js'],  
  13.       },  
  14.     },  
  15.   },  
  16. });  


 

2.7 文件数组格式

这种格式也可以在一个目标中配置多个 源文件到目标文件的映射。而且可以使用附加属性。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   concat: {  
  3.     foo: {  
  4.       files: [  
  5.         {src: ['src/aa.js''src/aaa.js'], dest: 'dest/a.js'},  
  6.         {src: ['src/aa1.js''src/aaa1.js'], dest: 'dest/a1.js'},  
  7.       ],  
  8.     },  
  9.     bar: {  
  10.       files: [  
  11.         {src: ['src/bb.js''src/bbb.js'], dest: 'dest/b/', nonull: true},  
  12.         {src: ['src/bb1.js''src/bbb1.js'], dest: 'dest/b1/', filter: 'isFile'},  
  13.       ],  
  14.     },  
  15.   },  
  16. });  


2.8 过时的格式

下面这个是在多任务和多目标出现之前的一种过时的格式,这种配置的目标文件路径实际上是目标名,所以会导致 grunt task:target 这样的命令出错,不建议使用这种格式。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   concat: {  
  3.     'dest/a.js': ['src/aa.js''src/aaa.js'],  
  4.     'dest/b.js': ['src/bb.js''src/bbb.js'],  
  5.   },  
  6. });  


2.9 自定义的过滤方法

filter 属性可以帮你定义很高级的文件细节。最简单的,可以直接使用一个 fs.Stats 方法名。下面这段代码只会匹配真实的文件。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   clean: {  
  3.     foo: {  
  4.       src: ['tmp/**/*'],  
  5.       filter: 'isFile',  
  6.     },  
  7.   },  
  8. });  


或者你可以创建一个自己的方法,对于应该被匹配的文件返回 true,对于不该被匹配的文件返回false。比如下面这个例子只会匹配到空文件夹。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   clean: {  
  3.     foo: {  
  4.       src: ['tmp/**/*'],  
  5.       filter: function(filepath) {  
  6.         return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);  
  7.       },  
  8.     },  
  9.   },  
  10. });  


2.10 globbing 模式(不太好翻译,类似正则式)

有时候很难把所有的源文件都一一列举出来,所以 Grunt 支持 通过 node-glob(https://github.com/isaacs/node-glob) 和 minimatch(https://github.com/isaacs/minimatch) 来进行文件名描述(又称 globbing)。

这不是一个很好理解的 globbing 模式教程,在一个文件路径中:

  • "*" 匹配任意字符,除了 "/"
  • "?" 匹配按个字符,除了"/"
  • "**" 匹配任意字符,包括"/"
  • "{}" 一个以 逗号分隔的 “或”逻辑
  • "!" 在模式的开头表示否定。

大家都知道,foo/*.js 会匹配 foo/ 目录下以 .js 结尾的任何文件(但是不包括子目录),而 foo/**/*.js 会匹配foo以及其子目录下的任何以 .js 结尾的文件。

并且,为了简化复杂的globbing 模式,Grunt 允许在一个列表中写多个 globbing 模式。这些模式会按顺序被处理。以 "!" 开头的会被排除。

[javascript] view plaincopy
  1. // You can specify single files:  
  2. {src: 'foo/this.js', dest: ...}  
  3. // Or arrays of files:  
  4. {src: ['foo/this.js''foo/that.js''foo/the-other.js'], dest: ...}  
  5. // Or you can generalize with a glob pattern:  
  6. {src: 'foo/th*.js', dest: ...}  
  7.   
  8. // This single node-glob pattern:  
  9. {src: 'foo/{a,b}*.js', dest: ...}  
  10. // Could also be written like this:  
  11. {src: ['foo/a*.js''foo/b*.js'], dest: ...}  
  12.   
  13. // All .js files, in foo/, in alpha order:  
  14. {src: ['foo/*.js'], dest: ...}  
  15. // Here, bar.js is first, followed by the remaining files, in alpha order:  
  16. {src: ['foo/bar.js''foo/*.js'], dest: ...}  
  17.   
  18. // All files except for bar.js, in alpha order:  
  19. {src: ['foo/*.js''!foo/bar.js'], dest: ...}  
  20. // All files in alpha order, but with bar.js at the end.  
  21. {src: ['foo/*.js''!foo/bar.js''foo/bar.js'], dest: ...}  
  22.   
  23. // Templates may be used in filepaths or glob patterns:  
  24. {src: ['src/<%= basename %>.js'], dest: 'build/<%= basename %>.min.js'}  
  25. // But they may also reference file lists defined elsewhere in the config:  
  26. {src: ['foo/*.js''<%= jshint.all.src %>'], dest: ...}  


关于 glob 模式语法,参见 node-glob(https://github.com/isaacs/node-glob) 和 minimatch(https://github.com/isaacs/minimatch)

 

2.11 动态创建文件

如果你想处理大量的单个文件,可以用一些附加属性来帮助动态创建文件。这些属性在“简洁格式“和”文件数组格式“下都可用。

  • expand:设为 true 来启用下面这些属性。
  • cwd:所有的 src 都相对于此路径(但是不包含)。
  • src:需要匹配的模式,相对于cwd。
  • dest:目标文件。
  • ext:在dest中的所有文件后缀都替换掉。
  • flatten:在dest中的所有路径的片段都替换掉。
  • rename:每当匹配到一个src时,都会调用此方法(在ext和flatten执行之后)。dest和src属性会被当参数传入,这个函数必须返回一个新的dest值。如果相同的dest被返回超过一次,每一个用它的src都会被添加到一个源数组。

再下面这个例子中,名为 minify 的任务static_mapping和 dynamic_mapping 执行的完全相同的任务。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   minify: {  
  3.     static_mappings: {  
  4.       // Because these src-dest file mappings are manually specified, every  
  5.       // time a new file is added or removed, the Gruntfile has to be updated.  
  6.       files: [  
  7.         {src: 'lib/a.js', dest: 'build/a.min.js'},  
  8.         {src: 'lib/b.js', dest: 'build/b.min.js'},  
  9.         {src: 'lib/subdir/c.js', dest: 'build/subdir/c.min.js'},  
  10.         {src: 'lib/subdir/d.js', dest: 'build/subdir/d.min.js'},  
  11.       ],  
  12.     },  
  13.     dynamic_mappings: {  
  14.       // Grunt will search for "**/*.js" under "lib/" when the "minify" task  
  15.       // runs and build the appropriate src-dest file mappings then, so you  
  16.       // don't need to update the Gruntfile when files are added or removed.  
  17.       files: [  
  18.         {  
  19.           expand: true,     // Enable dynamic expansion.  
  20.           cwd: 'lib/',      // Src matches are relative to this path.  
  21.           src: ['**/*.js'], // Actual pattern(s) to match.  
  22.           dest: 'build/',   // Destination path prefix.  
  23.           ext: '.min.js',   // Dest filepaths will have this extension.  
  24.         },  
  25.       ],  
  26.     },  
  27.   },  
  28. });  


任何静态和动态的方式都可以结合使用。

 

2.12 模板

通过 <% %> 来定义模板,任务执行时会自动把从配置中读取数据并拓展掉模板。模板会被递归拓展,直到没有任何模板为止。

整个config对象就是使用模板的上下文。并且,Grunt 和 它的方法都可以在模板中使用,比如 <% grunt.template.today("yyy-mm-dd") %>。

  • <%= xx %> 以config对象为上下文解析出 xx 的值,类型无关。字符串、数组或者对象都可。
  • <% %> 执行任意的js代码,可以用来进行流程控制或者执行循环等。

下面这个例子是一个concat任务,执行 grunt concat:sample 会把所有符合 foo/*.js+bar/*.js+baz/*.js的文件连接起来,再加上 /* abcde */ 的baner,最后生成 build/abcde.js文件。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   concat: {  
  3.     sample: {  
  4.       options: {  
  5.         banner: '/* <%= baz %> */\n',   // '/* abcde */\n'  
  6.       },  
  7.       src: ['<%= qux %>''baz/*.js'],  // [['foo/*.js', 'bar/*.js'], 'baz/*.js']  
  8.       dest: 'build/<%= baz %>.js',      // 'build/abcde.js'  
  9.     },  
  10.   },  
  11.   // Arbitrary properties used in task configuration templates.  
  12.   foo: 'c',  
  13.   bar: 'b<%= foo %>d'// 'bcd'  
  14.   baz: 'a<%= bar %>e'// 'abcde'  
  15.   qux: ['foo/*.js''bar/*.js'],  
  16. });  


 

2.13 导入外部数据

在下面这个例子中,项目的元数据是通过 package.json 文件导入的。uglify(http://github.com/gruntjs/grunt-contrib-uglify)插件的作用是压缩一个源文件,并且可以通过元数据的配置来添加一个banner。

Grunt 有 grunt.file.readJSON 和 grunt.file.readYAML 来分别导入 json和yaml文件。

[javascript] view plaincopy
  1. grunt.initConfig({  
  2.   pkg: grunt.file.readJSON('package.json'),  
  3.   uglify: {  
  4.     options: {  
  5.       banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'  
  6.     },  
  7.     dist: {  
  8.       src: 'src/<%= pkg.name %>.js',  
  9.       dest: 'dist/<%= pkg.name %>.min.js'  
  10.     }  
  11.   }  
  12. }); 
posted @ 2014-09-03 17:12  阳光小屋  阅读(852)  评论(0编辑  收藏  举报