前言
在翻译官文的前提下,增加自己的理解。http://gruntjs.com/configuring-tasks
Grunt Configuration
1 | grunt.initConfig({ |
- Task configuration is specified in your Gruntfile via the
grunt.initConfig
method - because this is JavaScript, you’re not limited to JSON; you may use any valid JavaScript here.
Task Configuration: Tasks and Targets
1 | grunt.initConfig({ |
the concat
task has foo
and bar
targets, while the uglify
task only has a bar
target。
这里可以看出Task
和Target
之间的定义,一个 Configuration 中可以有多个Task
,而每个Task
可以拥有多个Target
。
grunt concat:foo
或者grunt concat:bar
命令可以只执行该指定的 Target;grunt concat
命令将会同时执行foo
和bar
两个 Target。
Options
1 | grunt.initConfig({ |
Inside a task configuration, an options
property may be specified to override built-in defaults. In addition, each target may have an options
property which is specific to that target. Target-level options will override task-level options.
options 属性可以覆盖内置的默认选项,每一个 target 都可以定义 options
,不过 Target-level options 将会覆盖 task-level options。
Files
这里指源地址src
和目的地址desc
中的Files
Difference Between Grunt and Task Options
In addition to the files to work on, each task has its own specific needs. A task author may want to allow its user to configure some options to override the default behavior. These task-specific options shall not be confused with the Grunt options described before.
task 的作者希望使用他的人,可以通过options
去重载它的默认行为。1
2
3
4
5
6
7
8
9
10
11grunt.initConfig({
jshint: {
ignore_warning: {
options: {
'-W015': true,
},
src: 'js/**',
filter: 'isFile'
}
}
});
This configuration employs the Grunt options src and filter to specify the files to process. It also uses the grunt-contrib-jshint task-specific option -W015 to ignore a specific warning (the one having code W015).
补充:总觉得官方这里的标题有问题,这里不就是再进一步描述 options 的作用吗?怎么和 Difference 扯上关系了?
Compact Format
This form allows a single src-dest (source-destination) file mapping per-target1
2
3
4
5
6
7
8
9
10
11
12
13grunt.initConfig({
jshint: {
foo: {
src: ['src/aa.js', 'src/aaa.js']
},
},
concat: {
bar: {
src: ['src/bb.js', 'src/bbb.js'],
dest: 'dest/b.js',
},
},
});
- It is most commonly used for read-only tasks, like grunt-contrib-jshint, where a single
src
property is needed, and nodest
key is relevant。
可以之定义src
,表示只读,jshint
只需要源文件输入,检查代码的语法。 - 也可以是
src-dest
,concat
合并源文件到输出目录,所以需要src
和dest
。
File Object Format
This form supports multiple src-dest mappings per-target, where the property name is the destination file, and its value is the source file(s).1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16grunt.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'],
},
},
},
});
属性名称是目的文件'dest/a.js'
,属性值是源文件'src/aa.js', 'src/aaa.js'
,也可以通过File Array Format或者Older Format进行配置
File Array Format
1 | grunt.initConfig({ |
Older Format
1 | grunt.initConfig({ |
Custom Filter Function
The filter
property can help you target files with a greater level of detail.
Simply use a valid fs.Stats method name
1
2
3
4
5
6
7
8grunt.initConfig({
clean: {
foo: {
src: ['tmp/**/*'],
filter: 'isFile',
},
},
});create your own filter function and return true or false whether the file should be matched
For example the following will only clean folders that are empty:1
2
3
4
5
6
7
8
9
10grunt.initConfig({
clean: {
foo: {
src: ['tmp/**/*'],
filter: function(filepath) {
return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);
},
},
},
});utilizes the globbing and expand: true features—allows you to avoid overwriting files which already exist in the destination
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18grunt.initConfig({
copy: {
templates: {
files: [{
expand: true,
cwd: ['templates/css/'], // Parent folder of original CSS templates
src: '**/*.css', // Collects all `*.css` files within the parent folder (and its subfolders)
dest: 'src/css/', // Stores the collected `*.css` files in your `src/css/` folder
filter: function (dest) { // `dest`, in this instance, is the filepath of each matched `src`
var cwd = this.cwd, // Configures variables (these are documented for your convenience only)
src = dest.replace(new RegExp('^' + cwd), '');
dest = grunt.task.current.data.files[0].dest;
return (!grunt.file.exists(dest + src)); // Copies `src` files ONLY if their destinations are unoccupied
}
}]
}
}
});
Globbing patterns
*
matches any number of characters, but not /?
matches a single character, but not /**
matches any number of characters, including /, as long as it’s the only thing in a path part{}
allows for a comma-separated list of “or” expressions!
at the beginning of a pattern will negate the match
foo/*.js
will match all files ending with .js in the foo/ subdirectoryfoo/**/*.js
will match all files ending with .js in the foo/ subdirectory and all of its subdirectories.
more examples,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// You can specify single files:
{src: 'foo/this.js', dest: ...}
// Or arrays of files:
{src: ['foo/this.js', 'foo/that.js', 'foo/the-other.js'], dest: ...}
// Or you can generalize with a glob pattern:
{src: 'foo/th*.js', dest: ...}
// This single node-glob pattern:
{src: 'foo/{a,b}*.js', dest: ...}
// Could also be written like this:
{src: ['foo/a*.js', 'foo/b*.js'], dest: ...}
// All .js files, in foo/, in alpha order:
{src: ['foo/*.js'], dest: ...}
// Here, bar.js is first, followed by the remaining files, in alpha order:
{src: ['foo/bar.js', 'foo/*.js'], dest: ...}
// All files except for bar.js, in alpha order:
{src: ['foo/*.js', '!foo/bar.js'], dest: ...}
// All files in alpha order, but with bar.js at the end.
{src: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], dest: ...}
// Templates may be used in filepaths or glob patterns:
{src: ['src/<%= basename %>.js'], dest: 'build/<%= basename %>.min.js'}
// But they may also reference file lists defined elsewhere in the config:
{src: ['foo/*.js', '<%= jshint.all.src %>'], dest: ...}
For more on glob pattern syntax, see the node-glob and minimatch documentation.
Building the files object dynamically
When you want to process many individual files, a few additional properties may be used to build a files list dynamically;These properties may be specified in both Compact
and Files Array
mapping formats.。当你需要处理大量的文件的时候,一些额外的属性可以帮助你动态的进行处理;这些属性可以再Compact
和File Array
里面指定。expand
Set to true
will enable the following properties:
cwd
Allsrc
matches are relative to (but don’t include) this path.
意思就是说src
的寻址路径的根路径由cwd
指定src
Pattern(s) to match, relative to thecwd
.dest
Destination path prefix.ext
Replace any existing extension with this value in generated dest paths.
用ext
属性指定的扩展名将替换
当前文件的扩展名,并用此来生成dest
文件路径。extDot
Used to indicate where the period indicating the extension is located. Can take either ‘first’ (extension begins after the first period in the file name) or ‘last’ (extension begins after the last period), and is set by default to ‘first’ [Added in 0.4.3]
很简单,就是从后缀名中的第几个.
开始替换,比如,我们有文件myname.hello.world.js
,如果是 extDot 的值是first
,那么从.hello.world.js
开始替换,如果是last
,那么从.js
开始替换。flatten
Remove all path parts from generated dest paths.
从 dest paths 中删除所有的path parts
。(TODO: path parts 指的是什么?)rename
Embeds a customized function, which returns a string containing the new destination and filename. This function is called for each matched src file (after extension renaming and flattening). More informationrename
嵌入一个自定义的 function,返回一个包含新的 destination 和 文件名的 string,每一个匹配的 src 文件都会被执行,rename
是在 extension 重命名和 flattering 之后执行。
Any combination of static src-dest and dynamic src-dest file mappings may be specified.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29grunt.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
},
],
},
},
});
该用例同时包含了静态和动态文件处理的例子,静态处理流程必须手动指定 src 和 dest 的文件和路径;而动态处理可以动态的检测 src 中需要处理的文件,并且按照约定输出,上面的例子中就是动态的去获取lib/
目录中的源文件,并且从后缀名的第一个.
将其重命名为后缀名为.min.js
,并输出到build/
目录中。
The rename property
- Sample 1: the
copy
task will create a backup of README.md1
2
3
4
5
6
7
8
9
10
11
12
13grunt.initConfig({
copy: {
backup: {
files: [{
expand: true,
src: ['docs/README.md'], // The README.md file has been specified for backup
rename: function () { // The value for rename must be a function
return 'docs/BACKUP.txt'; // The function must return a string with the complete destination
}
}]
}
}
});
When the function is called, the dest and matched src path are passed in and can be used for returning the output string.
当该方法被调用后,dest 和 匹配的 src path 将会作为入参( 补充,rename: function(dest, src)
,但是上述用例并没有将他们作为入参来调用),并用来生成返回的 string;( 注意,这里返回的 string 就是最终要输出的 destination 目的地址。);
进一步解读,这个用例到底是什么意思?1
src: ['docs/README.md'], // The README.md file has been specified for backup
首先指定了需要被copy
的 src 文件,这里只指定了一个文件docs/README.md
。1
2
3rename: function () { // The value for rename must be a function
return 'docs/BACKUP.txt'; // The function must return a string with the complete destination
}
什么意思?其实就是将README.md
拷贝并重命名为BACKUP.txt
并输出到docs/
目的目录中。这个例子比较特殊,只是重命名了一个文件并作为输出。要注意的是,rename
这个方法比较特殊,不仅仅是重命名,而且需要输出 destination 的相关的信息。
- Sample 2: files are copied from the
dev
folder to thedist
folder, and renamed to have the word “beta” removed1
2
3
4
5
6
7
8
9
10
11
12
13
14
15grunt.initConfig({
copy: {
production: {
files: [{
expand: true,
cwd: 'dev/',
src: ['*'],
dest: 'dist/',
rename: function (dest, src) { // The `dest` and `src` values can be passed into the function
return dest + src.replace('beta',''); // The `src` is being renamed; the `dest` remains the same
}
}]
}
}
});
什么意思,起到了什么样的作用?将dev/
中的源文件去掉’beta’字样以后,拷贝到dest
目录中;所以,这里的样例很可能是这样的1
2
3├── dev
│ ├── hellobeta.js
│ ├── worldbeta.js
去掉其中beta
部分,然后再拷贝到dest
中。
Templates
Templates specified using <% %>
delimiters will be automatically expanded when tasks read them from the config。Templates 是由<% %>
符号指定的。grunt
and its methods are available inside templates, eg. <%= grunt.template.today('yyyy-mm-dd') %>
.
Given the sample concat task configuration below, running grunt concat:sample
will generate a file named build/abcde.js
by concatenating the banner /* abcde */
with all files matching foo/*.js
+ bar/*.js
+ baz/*.js
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16grunt.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'
},
},
// Arbitrary properties used in task configuration templates.
foo: 'c',
bar: 'b<%= foo %>d', // 'bcd'
baz: 'a<%= bar %>e', // 'abcde'
qux: ['foo/*.js', 'bar/*.js'],
});
Importing External Data
In the following Gruntfile, project metadata is imported into the Grunt config from a package.json
file, and the grunt-contrib-uglify plugin uglify
task is configured to minify a source file and generate a banner comment dynamically using that metadata.
Grunt has grunt.file.readJSON
and grunt.file.readYAML
methods for importing JSON and YAML data. 注意,这两个方法可以分别从json
和YAML
文件中读取配置文件。1
2
3
4
5
6
7
8
9
10
11
12grunt.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'
}
}
});