Grunt -- JavaScript 世界的构建工具

为何要用构建工具?

一句话:自动化。对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具可以减轻你的劳动,简化你的工作。当你在 Gruntfile 文件正确配置好了任务,任务运行器就会自动帮你或你的小组完成大部分无聊的工作。

为什么要使用Grunt?

Grunt生态系统非常庞大,并且一直在增长。由于拥有数量庞大的插件可供选择,因此,你可以利用Grunt自动完成任何事,并且花费最少的代价。如果找不到你所需要的插件,那就自己动手创造一个Grunt插件,然后将其发布到npm上吧。先看看入门文档吧。

原文出处:http://www.gruntjs.net/getting-started

快速入门

Grunt和 Grunt 插件是通过 npm 安装并管理的,npm是 Node.js 的包管理器。

Grunt 0.4.x 必须配合Node.js >= 0.8.0版本使用。;奇数版本号的 Node.js 被认为是不稳定的开发版。

在安装 Grunt 前,请确保当前环境中所安装的 npm 已经是最新版本,执行 npm update -g npm 指令进行升级(在某些系统中可能需要 sudo 指令)。

如果你已经安装了 Grunt,现在需要参考一些文档手册,那就请看一看 Gruntfile 实例 和如何 配置任务吧。

安装 CLI

还在使用 Grunt 0.3 版本吗?请查看 Grunt 0.3 注意事项

在继续学习前,你需要先将Grunt命令行(CLI)安装到全局环境中。安装时可能需要使用sudo(针对OSX、*nix、BSD等系统中)权限或者作为管理员(对于Windows环境)来执行以下命令。

npm install -g grunt-cli

上述命令执行完后,grunt 命令就被加入到你的系统路径中了,以后就可以在任何目录下执行此命令了。

注意,安装grunt-cli并不等于安装了 Grunt!Grunt CLI的任务很简单:调用与Gruntfile在同一目录中 Grunt。这样带来的好处是,允许你在同一个系统上同时安装多个版本的 Grunt。

这样就能让多个版本的 Grunt 同时安装在同一台机器上。

CLI 是如何工作的

每次运行grunt 时,他就利用node提供的require()系统查找本地安装的 Grunt。正是由于这一机制,你可以在项目的任意子目录中运行grunt 。

如果找到一份本地安装的 Grunt,CLI就将其加载,并传递Gruntfile中的配置信息,然后执行你所指定的任务。为了更好的理解 Grunt CLI的执行原理,请阅读源码

拿一份现有的 Grunt 项目练手

假定Grunt CLI已经正确安装,并且已经有一份配置好package.json 和 Gruntfile 文件的项目了,接下来就很容易拿Grunt练手了:

  1. 将命令行的当前目录转到项目的根目录下。
  2. 执行npm install命令安装项目依赖的库。
  3. 执行 grunt 命令。

OK,就是这么简单。还可以通过grunt --help 命令列出所有已安装的Grunt任务(task),但是一般更建议去查看项目的文档以获取帮助信息。

准备一份新的 Grunt 项目

一般需要在你的项目中添加两份文件:package.json 和 Gruntfile。

package.json: 此文件被npm用于存储项目的元数据,以便将此项目发布为npm模块。你可以在此文件中列出项目依赖的grunt和Grunt插件,放置于devDependencies配置段内。

Gruntfile: 此文件被命名为 Gruntfile.js 或 Gruntfile.coffee,用来配置或定义任务(task)并加载Grunt插件的。 此文档中提到的 Gruntfile 其实说的是一个文件,文件名是 Gruntfile.js 或Gruntfile.coffee。

package.json

package.json应当放置于项目的根目录中,与Gruntfile在同一目录中,并且应该与项目的源代码一起被提交。在上述目录(package.json所在目录)中运行npm install将依据package.json文件中所列出的每个依赖来自动安装适当版本的依赖。

下面列出了几种为你的项目创建package.json文件的方式:

  • 大部分 grunt-init 模版都会自动创建特定于项目的package.json文件。
  • npm init命令会创建一个基本的package.json文件。
  • 复制下面的案例,并根据需要做扩充,参考此说明.
{  "name": "my-project-name",  "version": "0.1.0",  "devDependencies": {    "grunt": "~0.4.5",    "grunt-contrib-jshint": "~0.10.0",    "grunt-contrib-nodeunit": "~0.4.1",    "grunt-contrib-uglify": "~0.5.0"  }}

安装Grunt 和 grunt插件

向已经存在的package.json 文件中添加Grunt和grunt插件的最简单方式是通过npm install <module> --save-dev命令。此命令不光安装了<module>,还会自动将其添加到devDependencies 配置段中,遵循tilde version range格式。

例如,下面这条命令将安装Grunt最新版本到项目目录中,并将其添加到devDependencies内:

npm install grunt --save-dev

同样,grunt插件和其它node模块都可以按相同的方式安装。下面展示的实例就是安装 JSHint 任务模块:

npm install grunt-contrib-jshint --save-dev

在 Grunt 插件 页面可以看到当前可用的 Grunt 插件,他们可以直接在项目中安装并使用。

安装插件之后,请务必确保将更新之后的 package.json 文件提交到项目仓库中。

Gruntfile

Gruntfile.js 或 Gruntfile.coffee 文件是有效的 JavaScript 或 CoffeeScript 文件,应当放在你的项目根目录中,和package.json文件在同一目录层级,并和项目源码一起加入源码管理器。

Gruntfile由以下几部分构成:

  • "wrapper" 函数
  • 项目与任务配置
  • 加载grunt插件和任务
  • 自定义任务

Gruntfile文件案例

在下面列出的这个 Gruntfile 中,package.json文件中的项目元数据(metadata)被导入到 Grunt 配置中, grunt-contrib-uglify 插件中的uglify 任务(task)被配置为压缩(minify)源码文件并依据上述元数据动态生成一个文件头注释。当在命令行中执行 grunt 命令时,uglify 任务将被默认执行。

module.exports = function(grunt) {  // Project configuration.  grunt.initConfig({    pkg: grunt.file.readJSON('package.json'),    uglify: {      options: {        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
'      },      build: {        src: 'src/<%= pkg.name %>.js',        dest: 'build/<%= pkg.name %>.min.js'      }    }  });  // 加载包含 "uglify" 任务的插件。  grunt.loadNpmTasks('grunt-contrib-uglify');  // 默认被执行的任务列表。  grunt.registerTask('default', ['uglify']);};

前面已经向你展示了整个 Gruntfile,接下来将详细解释其中的每一部分。

"wrapper" 函数

每一份 Gruntfile (和grunt插件)都遵循同样的格式,你所书写的Grunt代码必须放在此函数内:

module.exports = function(grunt) {  // Do grunt-related things in here};

项目和任务配置

大部分的Grunt任务都依赖某些配置数据,这些数据被定义在一个object内,并传递给grunt.initConfig 方法。

在下面的案例中,grunt.file.readJSON('package.json') 将存储在package.json文件中的JSON元数据引入到grunt config中。 由于<% %>模板字符串可以引用任意的配置属性,因此可以通过这种方式来指定诸如文件路径和文件列表类型的配置数据,从而减少一些重复的工作。

你可以在这个配置对象中(传递给initConfig()方法的对象)存储任意的数据,只要它不与你任务配置所需的属性冲突,否则会被忽略。此外,由于这本身就是JavaScript,你不仅限于使用JSON;你可以在这里使用任意的有效的JS代码。如果有必要,你甚至可以以编程的方式生成配置。

与大多数task一样,grunt-contrib-uglify 插件中的uglify 任务要求它的配置被指定在一个同名属性中。在这里有一个例子, 我们指定了一个banner选项(用于在文件顶部生成一个注释),紧接着是一个单一的名为build的uglify目标,用于将一个js文件压缩为一个目标文件。

// Project configuration.grunt.initConfig({  pkg: grunt.file.readJSON('package.json'),  uglify: {    options: {      banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
'    },    build: {      src: 'src/<%= pkg.name %>.js',      dest: 'build/<%= pkg.name %>.min.js'    }  }});

加载 Grunt 插件和任务

像 concatenation、[minification]、grunt-contrib-uglify 和 linting这些常用的任务(task)都已经以grunt插件的形式被开发出来了。只要在 package.json 文件中被列为dependency(依赖)的包,并通过npm install安装之后,都可以在Gruntfile中以简单命令的形式使用:

// 加载能够提供"uglify"任务的插件。grunt.loadNpmTasks('grunt-contrib-uglify');

注意: grunt --help 命令将列出所有可用的任务。

自定义任务

通过定义 default 任务,可以让Grunt默认执行一个或多个任务。在下面的这个案例中,执行 grunt 命令时如果不指定一个任务的话,将会执行uglify任务。这和执行grunt uglify 或者 grunt default的效果一样。default任务列表数组中可以指定任意数目的任务(可以带参数)。

// Default task(s).grunt.registerTask('default', ['uglify']);

如果Grunt插件中的任务(task)不能满足你的项目需求,你还可以在Gruntfile中自定义任务(task)。例如,在下面的 Gruntfile 中自定义了一个default 任务,并且他甚至不依赖任务配置:

module.exports = function(grunt) {  // A very basic default task.  grunt.registerTask('default', 'Log some stuff.', function() {    grunt.log.write('Logging some stuff...').ok();  });};

特定于项目的任务不必在 Gruntfile 中定义。他们可以定义在外部.js 文件中,并通过grunt.loadTasks方法加载。

配置任务

这个指南解释了如何使用 Gruntfile 来为你的项目配置task。如果你还不知道 Gruntfile 是什么,请先阅读 快速入门 指南并看看这个 Gruntfile 实例

Grunt配置

Grunt的task配置都是在 Gruntfile 中的grunt.initConfig方法中指定的。此配置主要是以任务名称命名的属性,也可以包含其他任意数据。一旦这些代表任意数据的属性与任务所需要的属性相冲突,就将被忽略。

此外,由于这本身就是JavaScript,因此你不仅限于使用JSON;你可以在这里使用任何有效的JavaScript。必要的情况下,你甚至可以以编程的方式生成配置。

grunt.initConfig({  concat: {    // 这里是concat任务的配置信息。  },  uglify: {    // 这里是uglify任务的配置信息  },  // 任意数据。  my_property: 'whatever',  my_src_files: ['foo/*.js', 'bar/*.js'],});

任务配置和目标

当运行一个任务时,Grunt会自动查找配置对象中的同名属性。多任务(multi-task)可以通过任意命名的“目标(target)”来定义多个配置。在下面的案例中,concat任务有名为foo和bar两个目标,而uglify任务仅仅只有一个名为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.    },  },});

同时指定任务(task)和目标(target),例如grunt concat:foo或者grunt concat:bar,将只会处理指定目标(target)的配置,而运行grunt concat将遍历所有目标(target)并依次处理。注意,如果一个任务使用grunt.task.renameTask重命名过,Grunt将在配置对象中查找以新的任务名命名的属性。

options属性

在一个任务配置中,options属性可以用来指定覆盖内置属性的默认值。此外,每一个目标(target)中还可以拥有一个专门针对此目标(target)的options属性。目标(target)级的平options将会覆盖任务级的options。

options对象是可选的,如果不需要,可以忽略。

grunt.initConfig({  concat: {    options: {      // 这里是任务级的Options,覆盖默认值     },    foo: {      options: {        // "foo" target options may go here, overriding task-level options.      },    },    bar: {      // No options specified; this target will use task-level options.    },  },});

文件

由于大多的任务都是执行文件操作,Grunt有一个强大的抽象层用于声明任务应该操作哪些文件。这里有好几种定义src-dest(源文件-目标文件)文件映射的方式,均提供了不同程度的描述和控制操作方式。任何一种多任务(multi-task)都能理解下面的格式,所以你只需要选择满足你需求的格式就行。

所有的文件格式都支持src和dest属性,此外"Compact"[简洁]和"Files Array"[文件数组]格式还支持以下一些额外的属性:

  • filter 它通过接受任意一个有效的fs.Stats方法名或者一个函数来匹配src文件路径并根据匹配结果返回true或者false。
  • nonull 如果被设置为 true,未匹配的模式也将执行。结合Grunt的--verbore标志, 这个选项可以帮助用来调试文件路径的问题。
  • dot 它允许模式模式匹配句点开头的文件名,即使模式并不明确文件名开头部分是否有句点。
  • matchBase如果设置这个属性,缺少斜线的模式(意味着模式中不能使用斜线进行文件路径的匹配)将不会匹配包含在斜线中的文件名。 例如,a?b将匹配/xyz/123/acb但不匹配/xyz/acb/123。
  • expand 处理动态的src-dest文件映射,更多的信息请查看动态构建文件对象
  • 其他的属性将作为匹配项传递给底层的库。 请查看node-glob 和minimatch 文档以获取更多信息。

简洁格式

这种形式允许每个目标对应一个src-dest文件映射。通常情况下它用于只读任务,比如grunt-contrib-jshint,它就只需要一个单一的src属性,而不需要关联的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',    },  },});

文件对象格式

这种形式支持每个目标对应多个src-dest形式的文件映射,属性名就是目标文件,源文件就是它的值(源文件列表则使用数组格式声明)。可以使用这种方式指定数个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'],      },    },  },});

文件数组格式

这种形式支持每个目标对应多个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文件格式在多任务和目标出现之前是一个过渡形式,目标文件路径实际上就是目标名称。遗憾的是, 由于目标名称是文件路径,那么运行grunt task:target可能不合适。此外,你也不能指定一个目标级的options或者给每个src-dest文件映射指定额外属性。

此种格式已经不赞成使用,请尽量不要使用。

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',    },  },});

或者创建你自己的filter函数,根据文件是否匹配来返回true或者false。下面的例子将仅仅清理一个空目录:

grunt.initConfig({  clean: {    foo: {      src: ['tmp/**/*'],      filter: function(filepath) {        return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);      },    },  },});

通配符模式

通常分别指定所有源文件路径是不切实际的,因此Grunt通过内置支持node-glob 和 minimatch 库来匹配文件名(又叫作globbing)。

然这并不是一个综合的匹配模式方面的教程,你只需要知道如何在文件路径匹配过程中使用它们即可:

  • * 匹配任意数量的字符,但不匹配 /
  • ? 匹配单个字符,但不匹配 /
  • ** 匹配任意数量的字符,包括 /,只要它是路径中唯一的一部分
  • {} 允许使用一个逗号分割的“或”表达式列表
  • ! 在模式的开头用于排除一个匹配模式所匹配的任何文件

每个人都需要知道的是:foo/*.js将匹配位于foo/目录下的所有的.js结尾的文件;而foo/**/*js将匹配foo/目录以及其子目录中所有以.js结尾的文件。

此外, 为了简化原本复杂的通配符模式,Grunt允许指定一个数组形式的文件路径或者一个通配符模式。所有模式按顺序处理,模式处理的过程中,带有!前缀的模式所匹配的文件将不包含在结果集中。 而且其结果集中的每一项也是唯一的。

例如:

// 指定单个文件:{src: 'foo/this.js', dest: ...}// 指定一个文件数组:{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: ...}

更多关于通配符模式的语法,请查看node-glob 和 minimatch 的文档。

动态构建文件对象

当你希望处理大量的单个文件时,这里有一些附加的属性可以用来动态的构建一个文件列表。这些属性都可以用于Compact和Files Array文件映射格式。

expand 设置为true用于启用下面的选项:

  • cwd 所有src指定的匹配都将相对于此处指定的路径(但不包括此路径) 。
  • src 相对于cwd路径的匹配模式。
  • dest 目标文件路径前缀。
  • ext 对于生成的dest路径中所有实际存在文件,均使用这个属性值替换扩展名。
  • extDot 用于指定标记扩展名的英文点号的所在位置。可以赋值 'first' (扩展名从文件名中的第一个英文点号开始) 或 'last' (扩展名从最后一个英文点号开始),默认值为 'first' [添加于 0.4.3 版本]
  • flatten 从生成的dest路径中移除所有的路径部分。
  • rename 对每个匹配的src文件调用这个函数(在重命名后缀和移除路径之后)。dest和匹配的src路径将被作为参数传入,此函数应该返回一个新的dest值。 如果相同的dest返回不止一次,那么,每个返回此值的src来源都将被添加到一个数组中作为源列表。

在下面的例子中,uglify 任务中的static_mappings和dynamic_mappings两个目标具有相同的src-dest文件映射列表, 这是因为任务运行时Grunt会自动展开dynamic_mappings文件对象为4个单独的静态src-dest文件映射--假设这4个文件能够找到。

可以指定任意静态src-dest和动态的src-dest文件映射相互结合。

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        },      ],    },  },});

模板

使用<% %>分隔符指定的模板会在任务从它们的配置中读取相应的数据时将自动扩展扫描。模板会被递归的展开,直到配置中不再存在遗留的模板相关的信息(与模板匹配的)。

整个配置对象决定了属性上下文(模板中的属性)。此外,在模板中使用grunt以及它的方法都是有效的,例如: <%= grunt.template.today('yyyy-mm-dd') %>。

  • <%= prop.subprop %> 将会自动展开配置信息中的prop.subprop的值,不管是什么类型。像这样的模板不仅可以用来引用字符串值,还可以引用数组或者其他对象类型的值。
  • <% %> 执行任意内联的JavaScript代码。对于控制流或者循环来说是非常有用的。

下面以concat任务配置为例,运行grunt concat:sample时将通过banner中的/* abcde */连同foo/*.js+bar/*.js+bar/*.js匹配的所有文件来生成一个名为build/abcde.js的文件。

grunt.initConfig({  concat: {    sample: {      options: {        banner: '/* <%= baz %> */
',   // '/* abcde */
'      },      src: ['<%= qux %>', 'baz/*.js'],  // [['foo/*.js', 'bar/*.js'], 'baz/*.js']      dest: 'build/<%= baz %>.js',      // 'build/abcde.js'    },  },  //用于任务配置模板的任意属性  foo: 'c',  bar: 'b<%= foo %>d', // 'bcd'  baz: 'a<%= bar %>e', // 'abcde'  qux: ['foo/*.js', 'bar/*.js'],});

导入外部数据

在下面的Gruntfile中,项目的元数据是从package.json文件中导入到Grunt配置中的,并且grunt-contrib-uglify 插件中的 uglify 任务被配置用于压缩一个源文件以及使用该元数据动态的生成一个banner注释。

Grunt有grunt.file.readJSON和grunt.file.readYAML两个方法分别用于引入JSON和YAML数据。

grunt.initConfig({  pkg: grunt.file.readJSON('package.json'),  uglify: {    options: {      banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
'    },    dist: {      src: 'src/<%= pkg.name %>.js',      dest: 'dist/<%= pkg.name %>.min.js'    }  }});

Gruntfile 实例

下面就针对一个 Gruntfile 案例做简单分析,也可以作为一个实例使用:

module.exports = function(grunt) {  grunt.initConfig({    jshint: {      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],      options: {        globals: {          jQuery: true        }      }    },    watch: {      files: ['<%= jshint.files %>'],      tasks: ['jshint']    }  });  grunt.loadNpmTasks('grunt-contrib-jshint');  grunt.loadNpmTasks('grunt-contrib-watch');  grunt.registerTask('default', ['jshint']);};

在页面底部是这个 Gruntfile 实例的完整内容,如果你按顺序阅读本文的话,可以跟随我们一步步分析这个文件中的每一部分。我们会用到以下5个 Grunt 插件:

第一部分是"wrapper" 函数,它包含了整个Grunt配置信息。

module.exports = function(grunt) {}

在这个函数中,我们可以初始化 configuration 对象:

grunt.initConfig({});

接下来可以从package.json 文件读入项目配置信息,并存入pkg 属性内。这样就可以让我们访问到package.json文件中列出的属性了,如下:

pkg: grunt.file.readJSON('package.json')

到目前为止我们就可以看到如下配置:

module.exports = function(grunt) {  grunt.initConfig({    pkg: grunt.file.readJSON('package.json')  });};

现在我们就可以为我们的每个任务来定义相应的配置(逐个定义我们为项目定义的任务配置),然后每个任务的配置对象作为Grunt配置对象(即grunt.initConfig({})所接受的配置对象)的属性,并且这个属性名称与任务名相同。因此"concat"任务就是我们的配置对象中的"concat"键(属性)。下面便是我的"concat"任务的配置对象。

concat: {  options: {    // 定义一个用于插入合并输出文件之间的字符    separator: ';'  },  dist: {    // 将要被合并的文件    src: ['src/**/*.js'],    // 合并后的JS文件的存放位置    dest: 'dist/<%= pkg.name %>.js'  }}

注意我是如何引用JSON文件(也就是我们在配置对象顶部引入的配置文件)中的name属性的。这里我使用pkg.name来访问我们刚才引入并存储在pkg属性中的package.json文件信息,它会被解析为一个JavaScript对象。Grunt自带的有一个简单的模板引擎用于输出配置对象(这里是指package.json中的配置对象)属性值,这里我让concat任务将所有存在于src/目录下以.js结尾的文件合并起来,然后存储在dist目录中,并以项目名来命名。

现在我们来配置uglify插件,它的作用是压缩(minify)JavaScript文件:

uglify: {  options: {    // 此处定义的banner注释将插入到输出文件的顶部    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */
'  },  dist: {    files: {      'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']    }  }}

这里我们让uglify在dist/目录中创建了一个包含压缩结果的JavaScript文件。注意这里我使用了<%= concat.dist.dest>,因此uglify会自动压缩concat任务中生成的文件。

QUnit插件的设置非常简单。 你只需要给它提供用于测试运行的文件的位置,注意这里的QUnit是运行在HTML文件上的。

qunit: {  files: ['test/**/*.html']},

JSHint插件的配置也很简单:

jshint: {  // define the files to lint  files: ['gruntfile.js', 'src/**/*.js', 'test/**/*.js'],  // configure JSHint (documented at http://www.jshint.com/docs/)  options: {      // more options here if you want to override JSHint defaults    globals: {      jQuery: true,      console: true,      module: true    }  }}

JSHint只需要一个文件数组(也就是你需要检测的文件数组), 然后是一个options对象(这个对象用于重写JSHint提供的默认检测规则)。你可以到JSHint官方文档站点中查看完整的文档。如果你乐于使用JSHint提供的默认配置,那么在Gruntfile中就不需要重新定义它们了.

最后,我们来看看watch插件:

watch: {  files: ['<%= jshint.files %>'],  tasks: ['jshint', 'qunit']}

你可以在命令行使用grunt watch来运行这个任务。当它检测到任何你所指定的文件(在这里我使用了JSHint任务中需要检测的相同的文件)发生变化时,它就会按照你所指定的顺序执行指定的任务(在这里我指定了jshint和qunit任务)。

最后, 我们还要加载所需要的Grunt插件。 它们应该已经全部通过npm安装好了。

grunt.loadNpmTasks('grunt-contrib-uglify');grunt.loadNpmTasks('grunt-contrib-jshint');grunt.loadNpmTasks('grunt-contrib-qunit');grunt.loadNpmTasks('grunt-contrib-watch');grunt.loadNpmTasks('grunt-contrib-concat');

最后设置了一些task。最重要的是default任务:

// 在命令行上输入"grunt test",test task就会被执行。grunt.registerTask('test', ['jshint', 'qunit']);// 只需在命令行上输入"grunt",就会执行default taskgrunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

下面便是最终完成的 Gruntfile 文件:

module.exports = function(grunt) {  grunt.initConfig({    pkg: grunt.file.readJSON('package.json'),    concat: {      options: {        separator: ';'      },      dist: {        src: ['src/**/*.js'],        dest: 'dist/<%= pkg.name %>.js'      }    },    uglify: {      options: {        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */
'      },      dist: {        files: {          'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']        }      }    },    qunit: {      files: ['test/**/*.html']    },    jshint: {      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],      options: {        //这里是覆盖JSHint默认配置的选项        globals: {          jQuery: true,          console: true,          module: true,          document: true        }      }    },    watch: {      files: ['<%= jshint.files %>'],      tasks: ['jshint', 'qunit']    }  });  grunt.loadNpmTasks('grunt-contrib-uglify');  grunt.loadNpmTasks('grunt-contrib-jshint');  grunt.loadNpmTasks('grunt-contrib-qunit');  grunt.loadNpmTasks('grunt-contrib-watch');  grunt.loadNpmTasks('grunt-contrib-concat');  grunt.registerTask('test', ['jshint', 'qunit']);  grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);};

创建任务

任务是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重命名过,Grunt将会自动在配置对象中查找新任务名称属性。

大部分的contrib任务(主要是指官方提供的任务),包括grunt-contrib-jshint插件的jshint任务,以及grunt-contrib-concat插件的concat任务都是多任务形式的。

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 中可以查看更多案例。

CLI 参数 / 环境

通过 process.env 来访问环境变量

请参考 使用命令行工具章节,查看完整的的命令行选项列表。

为什么我的异步task没有完成?

如果发生这种情况,可能是由于你忘记调用 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 文档

创建插件

  1. 通过 npm install -g grunt-init 命令安装 grunt-init 。
  2. 通过git clone git://github.com/gruntjs/grunt-init-gruntplugin.git ~/.grunt-init/gruntplugin 命令安装grunt插件模版。
  3. 在一个空的目录中执行 grunt-init gruntplugin 。
  4. 执行 npm install 命令以准备开发环境。
  5. 为你的插件书写代码。
  6. 执行 npm publish 命令将你创建的 Grunt 插件提发布npm!

注意

命名你的task

"grunt-contrib" 命名空间保留给 Grunt 团队维护的task使用,请给你自己的task起一个合适名字,并且避免使用被保留的命名空间。

调试

Grunt默认隐藏了error stack traces,但是可以通过 --stack 参数启用,方便你调试自己的task。如果你希望 Grunt 在出现错误时总是能记录下stack trace,可以在你的shell中创建一个命令别名(alias)。例如,在bash中,可以通过 alias grunt='grunt --stack' 命令创建一个别名。

存储任务文件

只在项目根目录中的 .grunt/[npm-module-name] 目录中存储数据文件,并在适当的时候将其清除。对于临时文件这并不是一个好的解决方案, 建议使用后面列出的几个常用npm模块(例如 temporarytmp)来调用操作系统级别的临时目录功能。

避免改变当前工作目录:process.cwd()

默认情况下,包含gruntfile文件的目录被设置为当前工作目录。用户可以在自己的gruntfile中通过执行grunt.file.setBase() 改变改变当前工作目录,但是插件不应该改变它。

path.resolve('foo') 可以被用来获取'foo' 相对于 Gruntfile 所在目录的绝对路径。

使用命令行工具

安装命令行工具

执行 sudo npm install -g grunt-cli 。

grunt命令行接口提供了一系列选项。你可以在你的终端中使用grunt -h查看这个选项。

--help, -h

显示帮助信息。

--base, -b

指定一个基本路径。默认情况下,所有文件路径都是相对于Gruntfile的。

还可以调用 grunt.file.setBase(...)

--no-color

禁用彩色输出。

--gruntfile

指定 Gruntfile 文件。

默认情况下,grunt会从当前目录或者父目录中寻找最近的Gruntfile.js或者Gruntfile.coffee文件。

--debug, -d

对支持调试的任务启用调试模式。

--stack

因警告或者致命错误退出时打印堆栈跟踪信息。

--force, -f

一种强制跳过警告信息的方式。

如果像从警告中得到提示,就不要使用这个选项,可以根据提示信息修正代码。

--tasks

指定一个包含可加载的任务和“额外”文件的目录。

还可以调用 grunt.loadTasks(...)

--npm

在通过npm安装的插件中检查可加载的任何以及额外文件。

还可以调用 grunt.loadNpmTasks(...)

--no-write

禁用写文件操作(可用于演示)。

--verbose, -v

冗长模式(Verbose mode)。会输出很多的信息。

--version, -V

打印grunt版本。结合 --verbose 一起使用可以获取更多信息。

--completion

输出shell的自动补全规则。更多信息参考grunt-cli相关的文档。

grunt

Grunt通过grunt对象暴露所有方法和属性,并将此对象赋予module.exports函数,这些方法和属性都将传递到你的Gruntfile、Grunt插件或者task文件中。

以下所有的方法几乎都是在别处定义的,但是为了方便使用,也在grunt对象中做了定义。详细的解释和案例请参阅各个api单独的文档。

Config

grunt.initConfig

此方法是 grunt.config.init 方法的别名(alias)。

创建task

grunt.registerTask

此方法是 grunt.task.registerTask 方法的别名(alias)。

grunt.registerMultiTask

此方法是 grunt.task.registerMultiTask 方法的别名(alias)。

grunt.renameTask

此方法是 grunt.task.renameTask 方法的别名(alias)。

Loading Externally-Defined Tasks

grunt.loadTasks

此方法是 grunt.task.loadTasks 方法的别名(alias)。

grunt.loadNpmTasks

此方法是 grunt.task.loadNpmTasks 方法的别名(alias)。

警告和致命错误

grunt.warn

此方法是 grunt.fail.warn 方法的别名(alias)。

grunt.fatal

此方法是 grunt.fail.fatal 方法的别名(alias)。

命令行参数

grunt.option

检索命令行参数的值,例如debug。注意对于每个命令行参数,都可以做相反的测试,例如no-debug

grunt.option(optionName)

杂项

grunt.package

package.json 中存储的元数据,其类型是对象。

grunt.package

grunt.version

当前 Grunt 的版本,类型是字符串。它仅仅是grunt.package.version属性的缩写。

grunt.version

grunt.config

从 Gruntfile 中获取针对当前项目的配置数据。

注意,任何标记为 ☃ (unicode snowman) 的方法也是可以直接通过 grunt 对象访问的;任何标记为 ☆ (white star) 的方法都可以在task内部通过 this 对象访问的。请知晓。

初始化配置数据

注意,下面列出的方法也可以通过 grunt 对象访问,访问形式为 grunt.initConfig

grunt.config.init

为当前项目初始化一个配置对象。其中传入的 configObject 参数可以用在后续的task中,可以通过grunt.config 方法访问。几乎每个项目的 Gruntfile 都会调用此方法。

grunt.config.init(configObject)

注意,任何 <% %> 模板字符串只会在取到配置数据后才被处理。

下面的案例展示了针对 grunt-contrib-jshint插件 中的 jshint task的配置数据:

grunt.config.init({  jshint: {    all: ['lib/*.js', 'test/*.js', 'Gruntfile.js']  }});

查看 Getting started 指南可以获取更多的配置案例。

此方法还可以以 grunt.initConfig 的形式访问。

获取配置数据

The following methods allow Grunt configuration data to be accessed either via dot-delimited string like'pkg.author.name' or via array of property name parts like ['pkg', 'author', 'name'].

Note that if a specified property name contains a . dot, it must be escaped with a literal backslash, eg.'concat.dist/built.js'. If an array of parts is specified, Grunt will handle the escaping internally with the grunt.config.escape method.

grunt.config

从项目的 Grunt 配置中获取或者设置一个值。这个方法作为其他方法的别名;如果传递两个参数,grunt.config.set被调用,另一方面grunt.config.get也被调用。Get or set a value from the project's grunt configuration. This method serves as an alias to other methods; if two arguments are passed, grunt.config.set is called, otherwise grunt.config.get is called.

grunt.config([prop [, value]])

grunt.config.get

Get a value from the project's Grunt configuration. If prop is specified, that property's value is returned, ornull if that property is not defined. If prop isn't specified, a copy of the entire config object is returned. Templates strings will be recursively processed using the grunt.config.process method.

grunt.config.get([prop])

grunt.config.process

Process a value, recursively expanding <% %> templates (via the grunt.template.process method) in the context of the Grunt config, as they are encountered. this method is called automatically bygrunt.config.get but not by grunt.config.getRaw.

grunt.config.process(value)

If any retrieved value is entirely a single '<%= foo %>' or '<%= foo.bar %>' template string, and the specified foo or foo.bar property is a non-string (and not null or undefined) value, it will be expanded to the actual value. That, combined with grunt's task system automatically flattening arrays, can be extremely useful.

grunt.config.getRaw

Get a raw value from the project's Grunt configuration, without processing <% %> template strings. Ifprop is specified, that property's value is returned, or null if that property is not defined. If prop isn't specified, a copy of the entire config object is returned.

grunt.config.getRaw([prop])

grunt.config.set

给当前项目的 Grunt 配置中的某个属性设置一个值。

grunt.config.set(prop, value)

注意,任何 <% %> 模板字符串只会在取到配置数据后才被处理。

grunt.config.escape

忽略给定的propString中的.点号。这应该用于包含点号的属性名。Escape . dots in the givenpropString. This should be used for property names that contain dots.

grunt.config.escape(propString)

grunt.config.merge

Added in 0.4.5

Recursively merges properties of the specified configObject into the current project configuration.

grunt.config.merge(configObject)

You can use this method to append configuration options, targets, etc., to already defined tasks, for example:

grunt.config.merge({  watch: {    files: ["path/to/files"],    tasks: ["task"]  }});

Requiring Config Data

注意,下面列出的方法都可以在task内部通过 this 对象访问,访问形式为 this.requiresConfig

grunt.config.requires

如果需要的配置属性有一个或多个不存在、值为null 或 undefined,当前task将失败。此方法可以指定一个或多个字符串、配置属性数组作为参数。

grunt.config.requires(prop [, prop [, ...]])

此方法在task内部以 this.requiresConfig 形式调用。

grunt.event

在这个页面中仅仅列出了最重要的方法,完整的 EventEmitter2 API 在 grunt.event 对象中都有定义。事件命名空间可以使用 .(英文句号)做分隔,并且可以使用命名空间通配符。

注意:Grunt目前并不发出任何事件,但是在你自己的task中仍然是有用的。

grunt.event.on

为指定的事件添加一个监听器,并将此监听器放倒监听器数组的尾部。

grunt.event.on(event, listener)

grunt.event.once

为指定的事件添加一个执行 一次 的监听器。次监听器只在事件头一次被触发后才会被调用,并且执行完之后被移除。

grunt.event.once(event, listener)

grunt.event.many

为指定的事件添加一个监听器,并在被移除之前执行 n 次 。

grunt.event.many(event, timesToListen, listener)

grunt.event.off

从监听器数组中移除所有监听某个指定事件的监听器。

grunt.event.off(event, listener)

grunt.event.removeAllListeners

移除所有的监听器,或者某个指定事件的所有监听器。

grunt.event.removeAllListeners([event])

grunt.event.emit

依次执行每一个可能监听此事件名的监听器,并将参数列表传给每个事件监听器。

grunt.event.emit(event, [arg1], [arg2], [...])

grunt.file

这里提供了很多用于读写文件、遍历文件系统和通过模式匹配查找文件的方法。其中很多方法都是Node.js中的文件操作函数的封装,但是提供了额外的错误处理、日志记录和字符编码转换。

注意:所有的文件路径都是参照 Gruntfile 文件的相对路径,除非通过 grunt.file.setBase 函数或在命令行中指定 --base 参数改变当前工作目录。

字符编码

grunt.file.defaultEncoding

设置此属性可以改变所有 grunt.file 方法的默认编码。默认是 'utf8'。如果必须改变这个值,建议你在Gruntfile文件中尽可能早改变。

grunt.file.defaultEncoding = 'utf8';

grunt.file.preserveBOM

添加于 0.4.2 版本

是否在 file.read 时保留字节顺序标记(BOM)。

grunt.file.preserveBOM = false;

读写文件

grunt.file.read

读取并返回文件的内容。返回值为一个字符串,如果 options.encoding 为 null ,则返回一个 Buffer

grunt.file.read(filepath [, options])

options 对象可以设置以下属性:

var options = {  // If an encoding is not specified, default to grunt.file.defaultEncoding.  // If specified as null, returns a non-decoded Buffer instead of a string.  encoding: encodingName};

grunt.file.readJSON

读取一个文件的内容,将其按照JSON格式解析,返回结果。参见 grunt.file.read 获取其所支持的参数列表。

grunt.file.readJSON(filepath [, options])

grunt.file.readYAML

读取一个文件的内容,将其按照YAML格式解析,返回结果。参见 grunt.file.read 获取其所支持的参数列表。

grunt.file.readYAML(filepath [, options])

grunt.file.write

将指定的内容写入文件中,如果需要,将创建文件路径中所有不存在的目录。字符串将按照指定的字符编码进行编码,Buffers 将会按照指定的方式写入磁盘。

如果指定了 --no-write 命令行参数,将不会真正写入文件。

grunt.file.write(filepath, contents [, options])

options 对象可设置以下属性:

var options = {  // If an encoding is not specified, default to grunt.file.defaultEncoding.  // If `contents` is a Buffer, encoding is ignored.  encoding: encodingName};

grunt.file.copy

将原文件拷贝到指定路径,如果需要,将创建文件路径中所有不存在的目录

如果指定了 --no-write 命令行参数,将不会真正写入文件。

grunt.file.copy(srcpath, destpath [, options])

options 对象可设置以下属性:

var options = {  // If an encoding is not specified, default to grunt.file.defaultEncoding.  // If null, the `process` function will receive a Buffer instead of String.  encoding: encodingName,  // The source file contents, source file path, and destination file path   // are passed into this function, whose return value will be used as the  // destination file's contents. If this function returns `false`, the file  // copy will be aborted.  process: processFunction,  // These optional globbing patterns will be matched against the filepath  // (not the filename) using grunt.file.isMatch. If any specified globbing  // pattern matches, the file won't be processed via the `process` function.  // If `true` is specified, processing will be prevented.  noProcess: globbingPatterns};

grunt.file.delete

删除指定的文件。文件和目录会被依次递归删除。

Will not delete the current working directory or files outside the current working directory unless the--force command-line option is specified.

如果指定了 --no-write 命令行参数,那么,文件路径将不会真的被删除。

grunt.file.delete(filepath [, options])

options 对象只可以设置以下属性:

var options = {  // Enable deleting outside the current working directory. This option may  // be overridden by the --force command-line option.  force: true};

目录操作

grunt.file.mkdir

工作方式类似 mkdir -p。创建一个目录和所有的中间目录。如果没有指定 mode ,默认是0777 & (~process.umask()).

如果没有 --no-write 命令行参数,目录不会被真正创建。

grunt.file.mkdir(dirpath [, mode])

grunt.file.recurse

递归遍历整个目录,对每个文件都执行 callback 函数。

grunt.file.recurse(rootdir, callback)

callback 函数接收以下参数:

function callback(abspath, rootdir, subdir, filename) {  // The full path to the current file, which is nothing more than  // the rootdir + subdir + filename arguments, joined.  abspath  // The root director, as originally specified.  rootdir  // The current file's directory, relative to rootdir.  subdir  // The filename of the current file, without any directory parts.  filename}

模式匹配

有时单独指定所有原始文件路径是不现实的,因此,Grunt通过内置的node-glob 库支持文件名 expansion (或者叫做 globbing) 。

参见 配置任务 指南中的 "Globbing patterns" 章节以获取 globbing pattern 实例。

grunt.file.expand

返回包含匹配给定通配符模式的文件或者目录路径的特殊数组。这个方法接收一个逗号分割的匹配模式或者一个匹配模式数组。如果路径匹配模式以!开头,它会从返回的数组排除所匹配的项。模式是按指定的顺序进行处理的, 因此包含和排除文件的顺序是很重要的。

grunt.file.expand([options, ] patterns)

文件路径都是参照 Gruntfile 文件的相对路径,除非通过 grunt.file.setBase 或 --base 命令行参数修改了当前工作目录。

options 对象支持所有 minimatch library 的参数,也支持额外的一些,如下:

  • filter E接受一个有效的 fs.Stats 方法名 或者一个已经通过了src文件路径匹配的函数,这个函数会返回truefalse
  • nonull 会保留src匹配模式,即使文件匹配失败。结合Grunt的-verbose标志,这个选项有助于文件路径问题的调试。
  • matchBase 不带斜线的模式只会匹配基本的名称部分。例如,这会使*.js就像**/*.js一样。
  • cwd 会让模式相对于当前路径进行模式匹配,所有返回的文件路径也是相对于当前路径的。

grunt.file.expandMapping

返回一个src-dest文件映射对象的数组。通过所指定的模式来匹配每一个源文件,然后将匹配的文件路径加入指定的dest中(dest存放匹配的文件路径)。这个文件路径会按照指定的选项加工或者重命名过。 查看grunt.file.expand方法文档可以了解如何指定patternsoptions

grunt.file.expandMapping(patterns, dest [, options])

注意:这个方法可以用于以编程的方式针对多任务的情况生成一个files数组,它会优先使用在配置任务指南中"动态构建文件对象"一节所描述的语法。

除了支持那些grunt.file.expand方法之外,options对象还支持下面这些属性:

var options = {  // The directory from which patterns are matched. Any string specified as  // cwd is effectively stripped from the beginning of all matched paths.  cwd: String,  // Remove the path component from all matched src files. The src file path  // is still joined to the specified dest.  flatten: Boolean,  // Remove anything after (and including) either the first or last "." in the   // destination path (indicated by options.extDot), then append this value.  ext: String,  // *Added in 0.4.3*  // Indicates where the period demarcating the extension is located. Can take:  // - 'first' (extension begins after the first period in the file name)   // - 'last' (extension begins after the last period)  // Default: 'first'  extDot: String,  // If specified, this function will be responsible for returning the final  // dest filepath. By default, it joins dest and matchedSrcPath like so:  rename: function(dest, matchedSrcPath, options) {    return path.join(dest, matchedSrcPath);  }};

grunt.file.match

针对一个或者多个文件路径来匹配一个或者多个匹配模式。返回一个特殊的数组,这个数组包含与指定的通配符模式任意匹配的所有文件路径。patternsfilepaths参数可以是一个单一的字符串或者也可以是一个字符串数组.如果匹配模式以!开头,就会从返回的数组从排除模式匹配的路径。模式会按指定的顺序进行处理,因此包含和排除文件的顺序是重要的。

grunt.file.match([options, ] patterns, filepaths)

options对象也支持minimatch库提供的所有选项。例如:如果options.matchBase为true,即使模式中不带斜线,这个模式也会匹配包含斜线的基本名称。例如:*.js模式将匹配path/to/file.js文件路径。

grunt.file.isMatch

这个方法与grunt.file.match方法包含同样的签名和逻辑,但是如果它匹配任意文件,就会简单的返回ture,否则返回false

判断文件类型

grunt.file.exists

检测给定的路径是否存在,返回boolean类型的值。

和Node.js 中的 path.join 方法一样,此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.exists(path1 [, path2 [, ...]])

grunt.file.isLink

给定的路径是否是符号链接,返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isLink(path1 [, path2 [, ...]])

如果路径不存在则返回false。

grunt.file.isDir

指定的路径是否是一个目录?返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isDir(path1 [, path2 [, ...]])

如果路径不存在它也会返回false。

grunt.file.isFile

指定的路径是否是一个文件? 返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isFile(path1 [, path2 [, ...]])

如果路径不存在将返回false。

路径

grunt.file.isPathAbsolute

指定的文件路径是否是绝对路径? 返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isPathAbsolute(path1 [, path2 [, ...]])

grunt.file.arePathsEquivalent

所有给出的路径是否都是同一个路径?返回boolean类型的值。

grunt.file.arePathsEquivalent(path1 [, path2 [, ...]])

grunt.file.doesPathContain

所有descendant路径是否全部包含在指定的ancestor路径中?返回boolean类型的值。

注意:不需要检查路径是否真的存在。

grunt.file.doesPathContain(ancestorPath, descendantPath1 [, descendantPath2 [, ...]])

grunt.file.isPathCwd

指定的文件路径是否是CWD?返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isPathCwd(path1 [, path2 [, ...]])

grunt.file.isPathInCwd

指定的文件路径是否在在CWD中?注意:CWD不在CWD 。返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isPathInCwd(path1 [, path2 [, ...]])

grunt.file.setBase

改变Grunt的当前工作目录(CWD)。默认情况下,所有文件路径都是参照 Gruntfile 文件的相对路径。此函数和 --base 命令行参数的工作方式一致。

grunt.file.setBase(path1 [, path2 [, ...]])

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

外部工具库

不建议使用

下面列出的所有外部工具库已经不再建议使用了。

请使用 npm 管理项目中对第三方工具库的依赖。

例如,如果你需要使用 Lo-Dash,首先通过 npm install lodash 安装,然后在 Gruntfile 文件中使用即可: var _ = require('lodash');

grunt.file.glob

不建议使用

glob - File globbing utility.

grunt.file.minimatch

不建议使用

minimatch - File pattern matching utility.

grunt.file.findup

不建议使用

findup-sync - Search upwards for matching file patterns.

grunt.log

向控制台输出信息。

参见 log lib source 以获取更多信息。

The log API

Grunt的输出应当看上去一致、美观。因此, 就有了这些log方法和一些有用的模式。所有用于输出日志的方法都可以链式调用。

注意:只有在命令行中指定 --verbose 选项时,所有 grunt.verbose 中的方法才会输出日志,并且完全像 grunt.log 中的方法一样工作。

grunt.log.write / grunt.verbose.write

输出指定的 msg 字符串日志,结尾不带换行符(newline)。

grunt.log.write(msg)

grunt.log.writeln / grunt.verbose.writeln

输出指定的 msg 字符串日志,结尾带换行符(newline)。

grunt.log.writeln([msg])

grunt.log.error / grunt.verbose.error

如果省略msg 字符串,将会以红色字体输出ERROR,否则输出>> msg,并且尾部带有换行符。

grunt.log.error([msg])

grunt.log.errorlns / grunt.verbose.errorlns

使用grunt.log.error记录一个错误日志,使用grunt.log.wraptext可以将日志以每行80个字符的形式输出。

grunt.log.errorlns(msg)

grunt.log.ok / grunt.verbose.ok

如果省略msg字符串,将会以绿色字体输出OK, 否则输出>> msg,并且尾部带有换行符。

grunt.log.ok([msg])

grunt.log.oklns / grunt.verbose.oklns

使用grunt.log.ok记录一条ok消息,使用grunt.log.wraptext可以将日志以每行80个字符的形式输出。

grunt.log.oklns(msg)

grunt.log.subhead / grunt.verbose.subhead

记录指定的msg字符串并加粗,尾部带有换行符。

grunt.log.subhead(msg)

grunt.log.writeflags / grunt.verbose.writeflags

记录obj的属性列表(用于调试标志最好)。

grunt.log.writeflags(obj, prefix)

grunt.log.debug / grunt.verbose.debug

记录一条调试信息,但是,仅当在命令行中指定 --debug选项时才会输出。

grunt.log.debug(msg)

Verbose 和 Notverbose

所有grunt.verbose下可用的日志记录方法的工作都酷似它们所对应的grunt.log方法,但是它们只在指定--verbose命令行选项的情况下才一样。还有一个对应"notverbose"适用于grunt.log.notverbosegrunt.log.verbose.or。实际上,.or属性也可以用于在verbosenotverbose两者之间有效的进行切换。

grunt.verbose / grunt.log.verbose

这个对象包含grunt.log下的所有方法,但是只在指定--verbose命令行选项情况下它才会输出日志信息。

grunt.verbose

grunt.verbose.or / grunt.log.notverbose

这个对象也包含grunt.log下的所有方法,但是只在不指定--verbose命令行选项情况下它才会输出日志信息。

grunt.verbose.or

工具方法

这些方法实际上不记录日志,它们只返回字符串,返回的字符串可以用于其他方法。

grunt.log.wordlist

Returns a comma-separated list of arr array items. arr 数组中的条目将会以逗号分割的形式返回。

grunt.log.wordlist(arr [, options])

options 对象拥有以下属性和默认值:

var options = {  // The separator string (can be colored).  separator: ', ',  // The array item color (specify false to not colorize).  color: 'cyan',};

grunt.log.uncolor

从字符串中移除所有颜色信息,使其适合检测其 .length 或写入日志文件。、

grunt.log.uncolor(str)

grunt.log.wraptext

以 width 个字符为一组将 text 字符串进行分解并添加   字符,除非绝对必要,否则将尽量确保不会从中间截断单词。

grunt.log.wraptext(width, text)

grunt.log.table

以 width 个字符为一组将 text 字符串进行分解。Wrap texts array of strings to columns widthscharacters wide. A wrapper for the grunt.log.wraptext method that can be used to generate output in columns.

grunt.log.table(widths, texts)

案例

通常的模式是,只有在 --verbose 模式或发生错误时才输出日志,如下所示:

grunt.registerTask('something', 'Do something interesting.', function(arg) {  var msg = 'Doing something...';  grunt.verbose.write(msg);  try {    doSomethingThatThrowsAnExceptionOnError(arg);    // Success!    grunt.verbose.ok();  } catch(e) {    // Something went wrong.    grunt.verbose.or.write(msg).error().error(e.message);    grunt.fail.warn('Something went wrong.');  }});

解释以上代码:

  1. grunt.verbose.write(msg); 只有在 --verbose 模式时才会输出日志信息(没有换行符)。
  2. grunt.verbose.ok(); 以绿色输出日志信息,末尾输出换行符。
  3. grunt.verbose.or.write(msg).error().error(e.message); 做了以下几件事:
    1. grunt.verbose.or.write(msg) 如果不在 --verbose 模式则输出日志信息,然后返回notverbose 对象。
    2. .error() 以红色输出ERROR日志,结尾输出换行符,然后返回 notverbose 对象。
    3. .error(e.message); 输出实际的错误信息(并返回 notverbose 对象)。
  4. grunt.fail.warn('Something went wrong.'); 以嫩黄色输出警告信息。除非在命令行指定了--force 选项,否则输出退出码1,然后退出 Grunt。

查看 grunt-contrib-* 任务的源码 以获取更多案例。

grunt.option

Grunt的option API被用来在多个任务之间共享参数、访问命令行中设置的参数。

一个简单的案例就是为一个目标(target)指定一个用于区别开发期还是过渡期的标志。在命令行中:grunt deploy --target=staging 会让grunt.option('target')返回"staging"

下面这个 Gruntfile 案例展示了如何使用 target 选项:

grunt.initConfig({  compass: {    dev: {      options: {        /* ... */        outputStyle: 'expanded'      },    },    staging: {      options: {        /* ... */        outputStyle: 'compressed'      },    },  },});var target = grunt.option('target') || 'dev';grunt.registerTask('deploy', ['compass:' + target]);

当你执行 grunt deploy 时,你的样式表将默认为dev目标并且输出易于阅读的CSS格式代码。如果你运行 grunt deploy --target=staging ,staging目标会被执行,输出压缩之后的CSS。

grunt.option 还可以在task中使用,如下:

grunt.registerTask('upload', 'Upload code to specified target.', function(n) {  var target = grunt.option('target');  // do something useful with target here});grunt.registerTask('deploy', ['validate', 'upload']);

注意,boolean参数可以仅指定key,而省略value。例如,在命令行执行 grunt deploy --staging 将会使grunt.option('staging') 返回 true

grunt.option

获取或设置一个选项。

grunt.option(key[, val])

boolean类型的选项可以通过在 key 前添加 no- 来取消。案例如下:

grunt.option('staging', false);var isDev = grunt.option('no-staging');// isDev === true

grunt.option.init

初始化 grunt.option。如果省略 initObject ,option将被初始化为一个空对象,否则将被设置为initObject

grunt.option.init([initObject])

grunt.option.flags

将所有参数作为命令行参数数组返回。

grunt.option.flags()

grunt.task

注册、执行和加载外部任务。

参见 task lib source 和 task util lib source 获取更多信息。

The task API

当一个任务正在执行时,Grunt 通过this 对象向此任务函数暴露了很多任务特定的属性和方法。参见 深入任务内幕指南,这里可以找到完整的属性和方法列表。

很多属性和方法都可以通过 this 对象访问到。

注意,任何标记为的 ☃ (unicode snowman) 方法也可以直接通过 grunt 对象直接访问到。参见 API首页以获取更多信息。

创建任务

grunt.task.registerTask

注册 "别名任务" 或 任务函数。此方法支持以下两种类型:

别名任务

如果指定了一个任务列表,那么,新注册的任务将会是这一个或多个任务的别名(alias)。当此"别名任务"执行时,taskList中的所有任务都将按指定的顺序依次执行。taskList 参数必须是一个任务数组。

grunt.task.registerTask(taskName, taskList)

下面这个案例展示的是定义一个"default" 任务,当执行 Grunt 且不通过参数指定任务时, "jshint"、 "qunit"、"concat" 和 "uglify" 任务将自动执行:

task.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

还可以指定任务的参数。下面的这个案例中,别名"dist"执行了 "concat" 和 "uglify" 这两个任务,并且都指定了"dist" 参数:

task.registerTask('dist', ['concat:dist', 'uglify:dist']);

任务函数

如果传入descriptiontaskFunction,每当任务运行时,指定的函数(taskFunction)都会被执行。此外,当执行 grunt --help时,前面指定的描述(description)就会显示出来。特定任务的属性和方法在任务函数内部通过this对象的属性即可访问。如果任务函数返回false表示任务失败。

注意,grunt.task.registerMultiTask方法将稍候介绍,它可以被用于定义一种特殊类型的任务,即"复合任务"。

grunt.task.registerTask(taskName, description, taskFunction)

下面这个案例中,当 Grunt 运行grunt foo:testing:123时,日志输出foo, testing 123。如果运行这个任务时不带参数,如grunt foo,日志输出foo, no args

grunt.task.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调用。

grunt.task.registerMultiTask

注册一个 "复合任务(multi task)"。 复合任务是指在不指定目标(target)时,将依次执行其所包含的所有已命名的子属性(sub-properties) (也就是 目标) 。除了默认的属性和方法外,还可以通过this对象访问复合任务独有的属性。

大多数的contrib任务,包括 jshint taskconcat task 和 uglify task 都是复合任务。

grunt.task.registerMultiTask(taskName, description, taskFunction)

给定以下配置信息,当执行grunt log:foo时,下面的复合任务将输出日志foo: 1,2,3;当执行grunt log:bar时,将输出日志bar: hello world。如果只是执行grunt log,那么,将先输出日志foo: 1,2,3,然后是bar: hello world,最后是baz: false

grunt.initConfig({  log: {    foo: [1, 2, 3],    bar: 'hello world',    baz: false  }});grunt.task.registerMultiTask('log', 'Log stuff.', function() {  grunt.log.writeln(this.target + ': ' + this.data);});

参见 创建任务 文档以获取更多复合任务的案例。

此方法还可以通过 grunt.registerMultiTask 调用。

grunt.task.requires

Fail the task if some other task failed or never ran.

grunt.task.requires(taskName);

grunt.task.exists

Added in 0.4.5

Check with the name, if a task exists in the registered tasks. Return a boolean.

grunt.task.exists(name)

grunt.task.renameTask

重命名任务。如果你希望覆盖某个任务的默认行为,并且希望保留原来的名字,这个函数将会很有用。

注意,如果一个任务已经被重命名了, this.name 和 this.nameArgs 属性都会发生相应的变化。

grunt.task.renameTask(oldname, newname)

此方法还可以通过 grunt.renameTask 调用。

加载外部定义的任务

对于多数项目来说,Gruntfile 文件中可能会定义很多任务。对于大型项目或者需要在多个项目中共享任务的情况,可以从一个或多个外部目录加载任务,或者从npm安装的 Grunt 插件加载任务。

grunt.task.loadTasks

从指定的目录(注意:相对于 Gruntfile 所在目录)加载任务相关的文件。此方法可以从本地Grunt插件加载任务相关的文件,只需指定包含"tasks"子目录的插件目录即可。

grunt.task.loadTasks(tasksPath)

此方法还可以通过 grunt.loadTasks 调用。

grunt.task.loadNpmTasks

从指定的 Grunt 插件中加载任务。此插件必须通过npm安装到本地,并且是参照 Gruntfile 文件的相对路径。Grunt插件还可以通过 grunt-init grunt插件模版创建: grunt init:gruntplugin

grunt.task.loadNpmTasks(pluginName)

此方法还可以通过 grunt.loadNpmTasks 调用。

队列任务

Grunt自动将命令行中指定的任务加入队列并执行,但是,一些独特的任务可以向队列中加入额外需要执行的任务。

grunt.task.run

将一个或多个任务放入队列中。 taskList 中的每个任务都会按照其在队列中的顺序,在当前任务执行完毕后立即执行。任务列表可以是一个任务数组或单个任务。

grunt.task.run(taskList)

grunt.task.clearQueue

完全清空任务队列。除非将额外的任务加入队列,否则将不会执行任何任务。

grunt.task.clearQueue()

grunt.task.normalizeMultiTaskFiles

将目标(target)的配置对象标准化为一个src-dest文件映射数组。此方法在内部由复合任务系统的this.files / grunt.task.current.files属性调用。

grunt.task.normalizeMultiTaskFiles(data [, targetname])

grunt.template

可以手工调用模板函数处理模版字符串。另外,config.get 方法(被很多任务所使用)会自动解析 <% %>类型的模版字符串,此类型的模版字符串是在 Gruntfile 中指的配置数据中定义的。

grunt.template.process

处理一个 Lo-Dash 模版 字符串。template 参数将被递归处理,知道没有任何模版位置。

默认的数据对象是整个配置对象,但是,如果设置了options.data,则使用该对象。默认的模板分隔符是<% %>,但是,如果options.delimiters被设置为自定义的形式(通过grunt.template.addDelimiters 进行设置),那么后续就会使用此模板分隔符。

grunt.template.process(template [, options])

在模板内部暴露了grunt对象,因此你可以这样做<%= grunt.template.tody('yyyy') %>注意, 如果数据对象已经有了grunt属性,那么在模板内部将无法访问grunt API。

在下面这个案例中,baz 属性被递归处理,直到再也没有多余的 <% %> 模版需要处理。

var obj = {  foo: 'c',  bar: 'b<%= foo %>d',  baz: 'a<%= bar %>e'};grunt.template.process('<%= baz %>', {data: obj}) // 'abcde'

grunt.template.setDelimiters

设置Lo-Dash模板的分隔符为预定义的形式,以防需要手动调用grunt.util._.templateconfig分隔符默认是<% %>

你可能永远不会使用这个方法,因为你所使用的 grunt.template.process 在内部使用的就是这个方法。

grunt.template.setDelimiters(name)

grunt.template.addDelimiters

Lo-Dash模板添加一个命名分隔符。你或许不需要使用这个方法,因为内置的分割符应该足以满足需求了,但是你仍可以随时添加{% %} 或者[% %]风格的分隔符。

name 参数应当是唯一的,因为这也是我们通过 grunt.template.setDelimiters 获取分隔符的方式,并且后续作为 grunt.template.process 的一个选项来使用。

grunt.template.addDelimiters(name, opener, closer)

在此实例中,如果我们希望使用 {% %} 形式的分隔符,我们需要如下这样设置:

grunt.template.addDelimiters('myDelimiters', '{%', '%}')

助手函数

grunt.template.date

使用dateformat library格式化一个日期。

grunt.template.date(date, format)

在这个案例中,指定的日期被格式化为 month/day/year。

grunt.template.date(847602000000, 'yyyy-mm-dd') // '1996-11-10'

grunt.template.today

使用 dateformat library格式化当前日期。

grunt.template.today(format)

在这个案例中,当前日期被格式化为4位数字表示的年份。

grunt.template.today('yyyy') // '2014'

grunt.util

各色工具函数/库,包括 Lo-Dash、Async 和 Hooker。

grunt.util.kindOf

返回给定值的"类型(kind)"。就像typeof,但是其返回的是内部的[Class](class/)值。可能返回的结果是"number""string""boolean""function""regexp""array""date""error""null""undefined"和可以表示一切类型的 "object"

grunt.util.kindOf(value)

grunt.util.error

返回一个新的Error实例(也可以抛出)与相应的消息。如果指定的是Error对象而不是message,则返回对象。

另外,如果为 origError 参数指定的是Error对象,并且使用 --stack 选项运行Grunt,则输出原始的Error堆栈。

grunt.util.error(message [, origError])

grunt.util.linefeed

将换行符转换为当前系统所采用的形式(Window上是 ,其他系统为 )。

grunt.util.normalizelf

对于一个给定的字符串,将其所有换行符转换为当前系统所采用的形式,然后返回一个新的字符串。(Window上是 ,其他系统为

grunt.util.normalizelf(string)

grunt.util.recurse

递归嵌套的对象和数组,为每个非对象值执行callbackFunction。如果continueFunction返回false, 给定的对象或值将会被跳过。

grunt.util.recurse(object, callbackFunction, continueFunction)

grunt.util.repeat

返回被重复n次的字符串str

grunt.util.repeat(n, str)

grunt.util.pluralize

给定一个"a/b"形式的str,如果n1,返回"a",否则返回"b"。如果不能使用'/',也可以指定一个自定义的分隔符。

grunt.util.pluralize(n, str, separator)

grunt.util.spawn

生成一个子进程,并跟踪其stdout、stderr和退出码。此方法返回子进程的引用。当子进程退出时,doneFunction 函数被调用。

grunt.util.spawn(options, doneFunction)

options 对象可以指定以下属性:

var options = {  // The command to execute. It should be in the system path.  cmd: commandToExecute,  // If specified, the same grunt bin that is currently running will be  // spawned as the child command, instead of the "cmd" option. Defaults  // to false.  grunt: boolean,  // An array of arguments to pass to the command.  args: arrayOfArguments,  // Additional options for the Node.js child_process spawn method.  opts: nodeSpawnOptions,  // If this value is set and an error occurs, it will be used as the value  // and null will be passed as the error value.  fallback: fallbackValue};

doneFunction 函数可以接收以下参数:

function doneFunction(error, result, code) {  // If the exit code was non-zero and a fallback wasn't specified, an Error  // object, otherwise null.  error  // The result object is an object with the properties .stdout, .stderr, and  // .code (exit code).  result  // When result is coerced to a string, the value is stdout if the exit code  // was zero, the fallback if the exit code was non-zero and a fallback was  // specified, or stderr if the exit code was non-zero and a fallback was  // not specified.  String(result)  // The numeric exit code.  code}

grunt.util.toArray

对于传入的数组或类数组对象,返回一个数组。对于将arguments对象转换为数组是非常有用的。

grunt.util.toArray(arrayLikeObject)

grunt.util.callbackify

标准化"返回值"和"传递结果给回调"的函数,总是传递一个结果给指定的回调函数。如果原始函数返回一个值,该值将即刻传递给回调函数,,并指定为最后一个参数,在所有的预定义参数之后。如果原始函数传递一个值给回调函数,,它也会继续照样如此。

grunt.util.callbackify(syncOrAsyncFunction)

下面这个例子也许能够更好的说明:

function add1(a, b) {  return a + b;}function add2(a, b, callback) {  callback(a + b);}var fn1 = grunt.util.callbackify(add1);var fn2 = grunt.util.callbackify(add2);fn1(1, 2, function(result) {  console.log('1 plus 2 equals ' + result);});fn2(1, 2, function(result) {  console.log('1 plus 2 equals ' + result);});

内部工具库

grunt.util.namespace

此内部工具库用于解析对象中深度嵌套的属性。

grunt.util.task

用于task执行的内部工具库。

外部工具库

不建议使用

下面列出的所有外部工具库已经不再建议使用了。

请使用 npm 管理项目中对第三方工具库的依赖。

例如,如果你需要使用 Lo-Dash,首先通过 npm install lodash 安装,然后在 Gruntfile 文件中使用即可: var _ = require('lodash');

grunt.util._

不建议使用

Lo-Dash - 很多有用的数组、函数和对象工具方法。 Underscore.string - 很多实用的字符串工具函数。

grunt.util._.str is available for methods that conflict with existing Lo-Dash methods.

grunt.util.async

不建议使用

Async - 对node和浏览器都适用的异步工具。

grunt.util.hooker

不建议使用

JavaScript Hooker - 用于调试和做些其他事情的钩子(hook)函数。

安装Grunt

这份文档详细解释了如何安装指定版本的 Grunt 和 Grunt 插件。如果你还没有阅读 快速入门 指南,请先将其看一遍。

概述

Grunt 和 Grunt 插件应当在项目的package.json文件中的devDependencies小节中定义。这样就可以通过一个命令将当前项目依赖的模块安装完毕:npm install。当前 Grunt 的稳定和开发版本都会在项目的wiki页面中列出。

安装指定版本的Grunt

如果你需要某个特定版本的 Grunt 或 Grunt 插件,执行npm install grunt@VERSION --save-dev 命令,其中VERSION代表你所需要的版本。这样就安装完成了,然后将其添加到package.json文件中的devDependencies小节中。

注意,当你在npm install命令后面添加了--save-dev 标记之后,package.json文件中出现的将是波浪线标记的版本范围 。一般情况下这样做很不错,当指定版本发布补丁更新后,新版本将被自动升级,并且按照semver定义的语义版本格式。

安装已经公布的开发版

随着新功能被开发出来,Grunt 会被定期的发布到npm上。如果不指定版本号,这种构建的版本是 根本不会被安装的,通常它们都会被指定构建码或 alpha/beta/release。

就像安装指定版本的 Grunt 一样,执行npm install grunt@VERSION --save-dev命令,其中VERSION 是你指定的版本,npm将在项目目录中安装此版本的grunt,并将其添加到package.json文件中的devDependencies小节。

注意,不管你指定的是什么版本,都将按照[波浪线标记的版本范围]将其添加到package.json文件中。这个危害很大,当指定的开发版出现新版本,尤其是不兼容的patch版本时,也会被npm安装,这就有可能扰乱你的项目,使其无法编译。

一旦出现这种情况,最重要的是要手工编辑 package.json文件,将 ~ (tilde)从版本号中去除掉。这样就能锁定到你所指定的某个具体的开发版本了。

这个技巧同样可以用于安装已经发布的 Grunt 插件的开发版本。

从github上直接安装

如果你需要安装最最最新的版本,而且这个 Grunt 或 Grunt 插件的版本并没有公布,按照下面的步骤来指定git URL 作为依赖 并且确保指定了具体的commit SHA (not a branch name) as the commit-ish。这将确保你的项目永远使用这个精确版本的grunt。

这个指定的git URL可以是官方的 Grunt 仓库,也可以是一个fork版本。

常见问题

如何安装grunt?

对于常规的安装说明,请阅读快速入门指南。如果在阅读完之后你需要更多的详细信息,你可以阅读更详细的的安装 Grunt指南。

什么时候我将可以使用开发中的'某某'特性?

安装 Grunt指南中介绍了如何安装已发布的和未发布的开发版本的Grunt。

Grunt可以在Windows上工作吗?

Grunt可以很好的在windows上工作,因为Node.jsnpm都能够很好的在windows上工作。通常情况下,问题在于Cygwin,因为它捆绑着一个较老版本的Node.js。

避免这个问题最好的办法是使用msysGit installer安装二进制的git和使用Node.js installer去安装二进制的nodenpm,然后使用内置的Windows command prompt 或 PowerShell 去替代Cygwin。

为什么我的异步任务不能执行完毕?

这是因为你忘记调用 this.async 方法来告知Grunt你的task是异步执行的。为了简化模型,Grunt采用同步模式的编码风格,你可以通过在任务中调用 this.async() 切换到异步模式。

注意,如果task执行失败,可以传递 false 给 done() 函数告知Grunt。

案例:

grunt.registerTask('asyncme', 'My asynchronous task.', function() {  var done = this.async();  doSomethingAsync(done);});

如何启用shell中的tab键自动补全功能?

为了给grunt增加tab键自动补功能,可以在你的~/.bashrc文件中添加下面一行代码:

eval "$(grunt --completion=bash)"

当然,假设你已经使用npm install -g grunt在全局安装好了Grunt。因为Grunt目前仅仅支持bash命令。

我如让多个任务共享参数?

虽然每个任务可以使用它自己的参数,但是,这里有几个方法允许你在多个task中共享参数。

"动态的" 任务别名

这是多个任务共享参数的首选方法

鉴于任务别名是很简单的,一个普通的task可以使用grunt.task.run让一个函数作为“动态的”任务别名。在下面这个案例中,在命令行中执行grunt build:001,最终效果是执行foo:001bar:001 和 baz:001这三个task。

grunt.registerTask('build', 'Run all my build tasks.', function(n) {  if (n == null) {    grunt.warn('Build num must be specified, like build:001.');  }  grunt.task.run('foo:' + n, 'bar:' + n, 'baz:' + n);});

-- 选项

多个任务共享参数的方式是使用grunt.option。在这里有一个例子,在命令行中执行grunt deploy --target=staging会让grunt.option('target')返回"staging"

grunt.registerTask('upload', 'Upload code to specified target.', function(n) {  var target = grunt.option('target');  // do something useful with target here});grunt.registerTask('deploy', ['validate', 'upload']);

注意,布尔类型的参数可以使用一个没有值的键。例如,在命令行中执行grunt deploy --staging会让grunt.option('staging') 返回true

全局和配置

在其他情况下,你可能希望暴露一个设置配置或者全局的值方法。 在这种情况下,可以在注册任务时设置其参数作为一个全局对象的或者项目配置的值。

在下面的例子中,在命令行运行grunt set_global:name:peter set_config:target:staging deploy会导致global.name的值为"peter"以及grunt.config('target')将会返回"staging"。由此推断,deploy任务就可以使用这些值。

grunt.registerTask('set_global', 'Set a global variable.', function(name, val) {  global[name] = val;});grunt.registerTask('set_config', 'Set a config property.', function(name, val) {  grunt.config.set(name, val);});

当出现错误时如何获取调用栈的追踪信息?

使用 --stack 参数就可以看到调用栈的追踪信息了。例如:grunt task --stack 。

为什么出现 "Maximum call stack size exceeded(超出最大调用栈大小)" 的错误?

你可能是为某个任务创建的别名和其他任务重名了。 例如:grunt.registerTask('uglify', ['uglify:my_target']); 应该是grunt.registerTask('myUglify', ['uglify:my_target']);

如何卸载或移除不需要的插件?

至少有两种方法。一种方法时利用 npm uninstall [GRUNT_PLUGIN] --save-dev 指令,这将从package.json 文件和 node_modules 目录下同时移除指定的插件。另一种方法时手工从 package.json文件中删除依赖项,然后执行 npm prune 指令。

出现错误 "Fail to install with npm error: No compatible version found"

请确保安装了最新稳定版本的 NPM 和 Node.JS


grunt 0.3 的相关问题

在Windows的 Grunt 0.3中,为什么当我尝试运行grunt时我的JS编辑器会打开?

如果你在Gruntfile所在的目录中时,当你输入grunt时Windows会尝试去执行那个文件。因此你需要输入grunt.cmd

另一个选择是使用DOSKEY命令去创建一个Grunt宏,请参考这篇文章。这样就可以使用grunt替代grunt.cmd了。

可以使用所示如下的DOSKEY命令:

DOSKEY grunt=grunt.cmd $*

项目脚手架

grunt-init

grunt-init是一个用于自动创建项目脚手架的工具。它会基于当前工作环境和你给出的一些配置选项构建一个完整的目录结构。至于其所生成的具体文件和内容,依赖于你所选择的模版和构建过程中你对具体信息所给出的配置选项。

注意:这个独立的程序曾经是作为Grunt内置的"init"任务而存在的。在从0.3升级到0.4指南中可以查看更多关于它演变的信息。

安装

为了使用grunt-init,需要将其安装到全局环境中。

npm install -g grunt-init

这样就会把grunt-init命令安装了到你的系统路径,从而允许你在任何目录中都可以运行它。

注意:你可能需要使用sudo权限或者作为超级管理员运行shell命令来执行这个操作。

用法

  • 使用grunt-init --help来获取程序帮助以及列出可用模板清单
  • 使用grunt-init TEMPLATE并基于可用模板创建一个项目
  • 使用grunt-init /path/to/TEMPLATE基于任意其他目录中可用的模板创建一个项目

注意,大多数的模板都应该在当前目录(执行命令的目录)中生成它们的文件(自动生成的项目相关的文件),因此,如果你不想覆盖现有的文件,注意一定要切换到一个新目录中来保证文件生成到其他目录。

安装模板

一旦模板被安装到你的~/.grunt-init/目录中(在Windows平台是%USERPROFILE%.grunt-init目录),那么就可以通过grunt-init命令来使用它们了。建议你使用git将模板克隆到项目目录中。例如, grunt-init-jquery模板可以像下面这样安装:

git clone https://github.com/gruntjs/grunt-init-jquery.git ~/.grunt-init/jquery

注意:如果你希望在本地像"foobarbaz"这样使用模板,你应该指定~/.grunt-init/foobarbaz之后再克隆。grunt-init会使用实际在于~/.grunt-init/目录中的实际的目录名。

下面是一些有Grunt官方维护的grunt-init模板:

定制模版

你可以创建和使用自定义模板。但是你的模板必须遵循与上述模板相同的文件结构。

下面是一个名为my-template的模板示例,它必须遵循下面这样的常规文件结构:

  • my-template/template.js - 主模板文件。
  • my-template/rename.json - 模板特定的重命名规则,作为模板进行处理。
  • my-template/root/ - f要复制到目标位置的文件。

假设这些文件存储在/path/to/my-template目录中,那么命令grunt-init /path/to/my-template就会处理这些模板。这个目录中可能存在多个命名唯一的模板(多个不重名的模板)。

此外,如果你把这个自定义模板放在你的~/.grunt-init/目录中(在Windows上是%USERPROFILE%.grunt-init目录),那么只需要使用grunt-init my-template命令就可以使用这个模版了。

复制文件

当执行初始化模板时, 只要模板使用init.filesToCopyinit.copyAndProcess方法,任何位于root/子目录中的文件都将被复制到当前目录。

注意所有被复制的文件都会被做为模板进行处理,并且所有{% %}模板都会依据props数据对象集合中的数据进行替换,除非设置了noProcess选项。可以看看jquery template中的案例。

重命名或者排除模板文件

rename.json用于描述sourcepathdestpath的重命名映射关系。sourcepath必须是相对于root/目录要被复制的文件路径,但是destpath值可以包含{% %}模板,用于描述目标路径是什么。

如果destpath被指定为false,那么文件就不会被复制。此外,srcpath还支持通配符匹配模式。

为询问信息指定默认选择

每个初始化提示都会有一个硬编码的默认值或者它会根据当前环境来尝试确定该缺省值。如果你想覆盖某个特定提示信息的默认值,你可以在OS X或者Linux的~/.grunt-init/defaults.json或者Windows的%USERPROFILE%.grunt-initdefaults.json文件中选择性的进行处理。

例如,由于我希望使用一个与众不同的名字来替代默认的名字,并且我还希望排除我的邮箱地址,同时我还希望自动指定一个作者的url,那么我的defaults.json看起来就可能像下面这样。

{  "author_name": ""Cowboy" Ben Alman",  "author_email": "none",  "author_url": "http://benalman.com/"}

注意:即使所有的内置提示信息都有文档,你还可以在源代码中找到他们的名字和默认值。

定义一个初始化模

exports.description

当用户运行grunt init或者grunt-init来显示所有可用的初始化模板时,这个简短的模板描述也会和模板名一起显示。

exports.description = descriptionString;

exports.notes

如果指定了这个选项,这个可选的扩展描述将会在任何提示信息显示之前显示出来。这是一个给用户提供一些解释命名空间相关帮助信息的很好的地方。这些提示可能是必选的也可能是可选的,等等。

exports.notes = notesString;

exports.warnOn

如果这个(推荐指定)可选的通配模式或者通配模式数组有匹配项出现,Grunt将终止并生成一个警告信息,用户可以使用--force来覆盖这个默认行为。这对于初始化模板可能覆盖现有文件的情况来说是非常有用的。

exports.warnOn = wildcardPattern;

然而最常见的值是'*',它能够匹配任意文件或者目录。使用minimatch通配符模式具有很大的灵活性。例如:

exports.warnOn = 'Gruntfile.js';        // Warn on a Gruntfile.js file.exports.warnOn = '*.js';            // Warn on any .js file.exports.warnOn = '*';               // Warn on any non-dotfile or non-dotdir.exports.warnOn = '.*';              // Warn on any dotfile or dotdir.exports.warnOn = '{.*,*}';          // Warn on any file or dir (dot or non-dot).exports.warnOn = '!*/**';           // Warn on any file (ignoring dirs).exports.warnOn = '*.{png,gif,jpg}'; // Warn on any image file.// This is another way of writing the last example.exports.warnOn = ['*.png', '*.gif', '*.jpg'];

exports.template

虽然exports属性定义在该函数的外面,然而所有实际的初始化代码指定在它内部。这个函数接受三个参数,grunt参数是一个grunt的引用,它包含所有的grunt方法和库init参数是一个包含特定于这个初始化模板而存在的方法和属性的对象。done参数是在初始化模板执行完成时必须调用的函数。

exports.template = function(grunt, init, done) {  // See the "Inside an init template" section.};

初始化模板的内部

init.addLicenseFiles

可以给files对象添加适当命名的许可协议证书文件。

var files = {};var licenses = ['MIT'];init.addLicenseFiles(files, licenses);// files === {'LICENSE-MIT': 'licenses/LICENSE-MIT'}

init.availableLicenses

返回一个可用许可协议证书的数组:

var licenses = init.availableLicenses();// licenses === [ 'Apache-2.0', 'GPL-2.0', 'MIT', 'MPL-2.0' ]

init.copy

它提供一份绝对或者相对源文件路径,以及一个可选的相对的目标文件路径,复制一个文件时,可以通过传递的回调函数来选择性的处理它。

init.copy(srcpath[, destpath], options)

init.copyAndProcess

遍历所传递对象中的所有文件,将源文件复制到目标路径,并处理相关内容。

init.copyAndProcess(files, props[, options])

init.defaults

用户在defaults.json中指定的默认初始值。

init.defaults

init.destpath

目标文件的绝对路径。

init.destpath()

init.expand

grunt.file.expand相同。

返回一个独一无二的与给定通配符模式所匹配的所有文件或目录路径数组。这个方法接收一个逗号分割的通配符模式或者数组形式的通配符模式参数。如果路径匹配模式以!开头,与模式所匹配的结果就会从返回的数组中排除。模式是按顺序处理的,所以包含和排除在数组中出现的顺序是非常重要的。

init.expand([options, ] patterns)

init.filesToCopy

返回一个包含待复制文件的对象,每个文件都包含了源文件的绝对路径和目标文件的相对路径,并按照rename.json(如果存在)中的规则进行重命名(或者忽略)。

var files = init.filesToCopy(props);/* files === { '.gitignore': 'template/root/.gitignore',  '.jshintrc': 'template/root/.jshintrc',  'Gruntfile.js': 'template/root/Gruntfile.js',  'README.md': 'template/root/README.md',  'test/test_test.js': 'template/root/test/name_test.js' } */

init.getFile

获取单一的任务文件路径。

init.getFile(filepath[, ...])

init.getTemplates

返回一个包含所有可用模板的对象。

init.getTemplates()

init.initSearchDirs

在初始化目录中搜索初始化模板。template是指模板的位置。还包括~/.grunt-init和grunt-init中的核心初始化任务。

init.initSearchDirs([filename])

init.process

启动程序并提示开始输入。

init.process(options, prompts, done)
init.process({}, [  // Prompt for these values  init.prompt('name'),  init.prompt('description'),  init.prompt('version')], function(err, props) {  // All finished, do something with the properties});

init.prompt

给用户一个提示,并让用户输入自己选择的值。

init.prompt(name[, default])

init.prompts

此对象包含了所有提示信息。

var prompts = init.prompts;

init.readDefaults

读取任务文件中(如果存在)读取JSON格式的默认值,并将它们合并到一个数据对象中。

init.readDefaults(filepath[, ...])

init.renames

模板的重命名规则。

var renames = init.renames;// renames === { 'test/name_test.js': 'test/{%= name %}_test.js' }

init.searchDirs

搜索模板的目录数组。

var dirs = init.searchDirs;/* dirs === [ '/Users/shama/.grunt-init',  '/usr/local/lib/node_modules/grunt-init/templates' ] */

init.srcpath

根据文件名搜索初始化模板路径并返回一个绝对路径。

init.srcpath(filepath[, ...])

init.userDir

返回用户模板目录的绝对路径。

var dir = init.userDir();// dir === '/Users/shama/.grunt-init'

init.writePackageJSON

在目标目录中保存一个package.json文件。回调函数可以用于后置处理属性的添加/移除/其他操作。

init.writePackageJSON(filename, props[, callback])

内置提示

author_email

用于package.json中的作者邮箱地址。默认情况下会尝试从用户的git配置中找到一个默认值。

author_name

用于package.json中的作者全名和版权信息。也会尝试从用户的git配置中找到一个默认值。

author_url

package.json中的用于公开作者个人网站的URL。

bin

项目根目录中cli脚本的相对路径。

bugs

用于项目问题跟踪的公开URL。如果项目有一个Github仓库,将自动指向项目Github的问题跟踪模块(issue)。

description

项目的描述。通常在package.json或者README文件中。

grunt_version

项目所需的有效Grunt版本范围定义。

homepage

指向项目首页的公开URL。如果此项目使用的是github仓库,那么,默认是Github仓库的url。

jquery_version

如果是jQuery项目,它表示项目所需的jQuery版本。必须是一个有效的版本范围定义。

licenses

项目许可协议证书。多个许可协议证书使用空格分割,内置的许可协议有:MITMPL-2.0GPL-2.0Apache-2.0。默认是MIT协议。可以使用init.addLicenseFiles方法添加自定义许可协议证书。

main

项目的主入口。默认是lib目录已项目名称命名的文件。

name

项目名称。在项目模版中将会大量使用,默认指向当前工作目录。

node_version

项目所需的Node.js版本。必须是一个有效的版本范围定义。

npm_test

项目中运行测试的命令,默认情况下是grunt

repository

项目的git仓库。默认是一个猜测的github url。

title

适合大家识别的项目名称。默认是原始项目名称,并且经过过滤,适合大家识别。

version

项目的版本号。默认是第一个有效的语义版本号:0.1.0

深入任务内幕

当一个任务执行时,Grunt通过 this 对象向此任务函数暴露了很多任务特定的属性和方法。 同样这个对象也将暴露为grunt.task.current的形式在 templates中使用,例如,this.name属性也可以作为grunt.task.current.name来使用。

所有任务内部都可以使用的方法/属性

this.async

如果一个任务是异步的,必须调用此方法以通知Grunt。此方法返回一个 "done" 函数,应当在任务执行完毕后调用。false 或 Error 对象都可以传递给done函数,以通知Grunt此任务执行失败。

如果 this.async 方法没有被调用,此任务将会同步执行。

// Tell Grunt this task is asynchronous.var done = this.async();// Your async code.setTimeout(function() {  // Let's simulate an error, sometimes.  var success = Math.random() > 0.5;  // All done!  done(success);}, 1000);

this.requires

如果一个任务依赖于另外一个(或一些)任务的成功执行,在其依赖的任务没有运行或者运行失败的情况下,这个方法可以被用来强制Grunt退出。作为这个方法的参数,其依赖的任务列表可以是一个包含多个任务名称的数组,也可以是单个的任务名称。

注意,实际上这个方法并不会运行指定任务列表中的任务,它只是在任务列表中的任务没有成功运行的时候通知系统当前的任务失败了。

this.requires(tasksList)

this.requiresConfig

这个方法可以指定一个或者多个字符串或者数组的配置属性为必需的。如果一个或多个必需的配置属性缺失,就通知系统当前任务失败。

this.requiresConfig(prop [, prop [, ...]])

查看grunt.config文档了解更多关于配置属性相关的信息。

这个方式是grunt.config.requires方法的一个别名。

this.name

当前任务的名称,和定义在grunt.registerTask中的任务名一致。例如,如果以grunt sample或者grunt sample:foo的方式运行一个名为"sample"的任务,那么在这个任务函数内部,this.name的值就是"sample"

注意,如果通过grunt.task.renameTask 重命名了一个task,此属性也会跟着变为新名字。

this.nameArgs

当前任务的名称,包括在命令行中指定的任意使用逗号分割的参数或者标记。例如,如果以grunt sample:foo的方式运行一个名为"sample"的任务,那么在这个任务函数内部,this.nameArgs的值就是"sample:foo"

注意,如果一个任务使用grunt.task.renameTask方法重命名过,那么这个属性也会指向对应的新名称。

this.args

传递给当前任务的参数数组。例如,以grunt sample:foo:bar的方式运行一个名为"sample"的任务,那么在这个任务函数内部,this.args的值就是["foo", "bar"]

注意,在多任务形式中,当前目标(名)会从this.args数组中省略。

this.flags

根据传递给当前任务的参数生成的一个对象。例如,以grunt sample:foo:bar的形式运行一个名为"sample"的任务,那么在这个任务函数内部,this.flags的值是{foo: true, bar: true}

注意,在多任务形式中,任务目标名不会被设置为一个标记。

this.errorCount

当前任务执行期间grunt.log.error方法被调用的次数。如果在任务运行期间有错误信息输出,它可以用来让任务执行失败。

this.options

返回一个options对象。defaultsObj是一个可选参数,它的属性会被任意的任务级options对象的属性覆盖;在多任务形式中,它的属性会进一步被目标级的options对象的属性覆盖。

this.options([defaultsObj])

下面给出了一个例子,展示了在任务中可以如何使用this.options方法:

var options = this.options({  enabled: false,});doSomething(options.enabled);

配置任务指南中,有一个例子展示了如何从用户任务的角度来指定options。

多任务形式内部可用的方法/属性

this.target

在一个多任务形式中,这个属性包含了当前正被遍历的目标的名称。例如,如果一个名为"sample"的多任务带有{sample: {foo: "bar"}}这样的配置数据,当以grunt sample:foo的形式运行这个任务时,那么在这个任务函数内部,this.target属性的值就为"foo"

this.files

在一个多任务形式中,使用Grunt支持的文件格式和选项通配符模式或者动态映射方式指定的文件,都会被自动标准化为一个唯一的格式:即文件数组格式

这意味着,任务不需要为了明确的处理自定义文件格式,通配符格式,源文件到目标文件映射或者过滤输出文件或者目录而包含大量模板。任务只需要根据配置任务指南中的说明指定文件,Grunt会自动处理所有任务细节。

this.files属性永远都是一个数组。你的任务应该利用数组中每个对象的srcdest属性遍历this.files数组。在你的任务关注每个目标文件的多个源文件的情况下,src`属性也永远是一个数组。

注意,有可能不存在的文件也被包含在 src 的值当中,因此,你应该在使用前检查源文件是否存在。

下面的例子展示了一个简单的"concat"任务是怎样使用this.files属性的:

this.files.forEach(function(file) {  var contents = file.src.filter(function(filepath) {    // Remove nonexistent files (it's up to you to filter or warn here).    if (!grunt.file.exists(filepath)) {      grunt.log.warn('Source file "' + filepath + '" not found.');      return false;    } else {      return true;    }  }).map(function(filepath) {    // Read and return the file's source.    return grunt.file.read(filepath);  }).join('
');  // Write joined contents to destination filepath.  grunt.file.write(file.dest, contents);  // Print a success message.  grunt.log.writeln('File "' + file.dest + '" created.');});

如果你还需要使用原始文件对象的属性,可以通过每个单独的文件对象的orig属性来获取并使用,但是目前都没发现有访问原始属性的用例。

this.filesSrc

在多任务形式中,在src中通过任意的文件格式指定的文件都会被归并到一个数组。如果你的任务是"只读"的并且无需关心目标文件路径,可以使用这个数组来替代this.files

下面这个例子展示了一个简单的"lint"的任务是怎样使用this.filesSrc属性的:

// Lint specified files.var files = this.filesSrc;var errorCount = 0;files.forEach(function(filepath) {  if (!lint(grunt.file.read(filepath))) {    errorCount++;  }});// Fail task if errors were logged.if (errorCount > 0) { return false; }// Otherwise, print a success message.grunt.log.ok('Files lint free: ' + files.length);

this.data

在多任务形式中,这是存储在给定目标的Grunt配置对象中的实际数据。例如,如果一个名为"sample"的多任务带有{sample: {foo: "bar"}}这样的配置数据,当以grunt sample:foo的形式运行这个任务时,那么在这个任务函数内部,this.data的值就为"bar"

推荐使用this.optionsthis.filesthis.filesSrc来替代this.data, 因为它们的值都是经过标准化的。

退出码

  • 0 - 无错误!
  • 1 - 致命错误
  • 2 - 未找到gruntfile
  • 3 - Task 错误
  • 4 - 模版处理错误
  • 5 - 无效的shell自动完成规则
  • 6 - 警告

Grunt -- JavaScript 世界的构建工具

为何要用构建工具?

一句话:自动化。对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具可以减轻你的劳动,简化你的工作。当你在 Gruntfile 文件正确配置好了任务,任务运行器就会自动帮你或你的小组完成大部分无聊的工作。

为什么要使用Grunt?

Grunt生态系统非常庞大,并且一直在增长。由于拥有数量庞大的插件可供选择,因此,你可以利用Grunt自动完成任何事,并且花费最少的代价。如果找不到你所需要的插件,那就自己动手创造一个Grunt插件,然后将其发布到npm上吧。先看看入门文档吧。

原文出处:http://www.gruntjs.net/getting-started

快速入门

Grunt和 Grunt 插件是通过 npm 安装并管理的,npm是 Node.js 的包管理器。

Grunt 0.4.x 必须配合Node.js >= 0.8.0版本使用。;奇数版本号的 Node.js 被认为是不稳定的开发版。

在安装 Grunt 前,请确保当前环境中所安装的 npm 已经是最新版本,执行 npm update -g npm 指令进行升级(在某些系统中可能需要 sudo 指令)。

如果你已经安装了 Grunt,现在需要参考一些文档手册,那就请看一看 Gruntfile 实例 和如何 配置任务吧。

安装 CLI

还在使用 Grunt 0.3 版本吗?请查看 Grunt 0.3 注意事项

在继续学习前,你需要先将Grunt命令行(CLI)安装到全局环境中。安装时可能需要使用sudo(针对OSX、*nix、BSD等系统中)权限或者作为管理员(对于Windows环境)来执行以下命令。

npm install -g grunt-cli

上述命令执行完后,grunt 命令就被加入到你的系统路径中了,以后就可以在任何目录下执行此命令了。

注意,安装grunt-cli并不等于安装了 Grunt!Grunt CLI的任务很简单:调用与Gruntfile在同一目录中 Grunt。这样带来的好处是,允许你在同一个系统上同时安装多个版本的 Grunt。

这样就能让多个版本的 Grunt 同时安装在同一台机器上。

CLI 是如何工作的

每次运行grunt 时,他就利用node提供的require()系统查找本地安装的 Grunt。正是由于这一机制,你可以在项目的任意子目录中运行grunt 。

如果找到一份本地安装的 Grunt,CLI就将其加载,并传递Gruntfile中的配置信息,然后执行你所指定的任务。为了更好的理解 Grunt CLI的执行原理,请阅读源码

拿一份现有的 Grunt 项目练手

假定Grunt CLI已经正确安装,并且已经有一份配置好package.json 和 Gruntfile 文件的项目了,接下来就很容易拿Grunt练手了:

  1. 将命令行的当前目录转到项目的根目录下。
  2. 执行npm install命令安装项目依赖的库。
  3. 执行 grunt 命令。

OK,就是这么简单。还可以通过grunt --help 命令列出所有已安装的Grunt任务(task),但是一般更建议去查看项目的文档以获取帮助信息。

准备一份新的 Grunt 项目

一般需要在你的项目中添加两份文件:package.json 和 Gruntfile。

package.json: 此文件被npm用于存储项目的元数据,以便将此项目发布为npm模块。你可以在此文件中列出项目依赖的grunt和Grunt插件,放置于devDependencies配置段内。

Gruntfile: 此文件被命名为 Gruntfile.js 或 Gruntfile.coffee,用来配置或定义任务(task)并加载Grunt插件的。 此文档中提到的 Gruntfile 其实说的是一个文件,文件名是 Gruntfile.js 或Gruntfile.coffee。

package.json

package.json应当放置于项目的根目录中,与Gruntfile在同一目录中,并且应该与项目的源代码一起被提交。在上述目录(package.json所在目录)中运行npm install将依据package.json文件中所列出的每个依赖来自动安装适当版本的依赖。

下面列出了几种为你的项目创建package.json文件的方式:

  • 大部分 grunt-init 模版都会自动创建特定于项目的package.json文件。
  • npm init命令会创建一个基本的package.json文件。
  • 复制下面的案例,并根据需要做扩充,参考此说明.
{  "name": "my-project-name",  "version": "0.1.0",  "devDependencies": {    "grunt": "~0.4.5",    "grunt-contrib-jshint": "~0.10.0",    "grunt-contrib-nodeunit": "~0.4.1",    "grunt-contrib-uglify": "~0.5.0"  }}

安装Grunt 和 grunt插件

向已经存在的package.json 文件中添加Grunt和grunt插件的最简单方式是通过npm install <module> --save-dev命令。此命令不光安装了<module>,还会自动将其添加到devDependencies 配置段中,遵循tilde version range格式。

例如,下面这条命令将安装Grunt最新版本到项目目录中,并将其添加到devDependencies内:

npm install grunt --save-dev

同样,grunt插件和其它node模块都可以按相同的方式安装。下面展示的实例就是安装 JSHint 任务模块:

npm install grunt-contrib-jshint --save-dev

在 Grunt 插件 页面可以看到当前可用的 Grunt 插件,他们可以直接在项目中安装并使用。

安装插件之后,请务必确保将更新之后的 package.json 文件提交到项目仓库中。

Gruntfile

Gruntfile.js 或 Gruntfile.coffee 文件是有效的 JavaScript 或 CoffeeScript 文件,应当放在你的项目根目录中,和package.json文件在同一目录层级,并和项目源码一起加入源码管理器。

Gruntfile由以下几部分构成:

  • "wrapper" 函数
  • 项目与任务配置
  • 加载grunt插件和任务
  • 自定义任务

Gruntfile文件案例

在下面列出的这个 Gruntfile 中,package.json文件中的项目元数据(metadata)被导入到 Grunt 配置中, grunt-contrib-uglify 插件中的uglify 任务(task)被配置为压缩(minify)源码文件并依据上述元数据动态生成一个文件头注释。当在命令行中执行 grunt 命令时,uglify 任务将被默认执行。

module.exports = function(grunt) {  // Project configuration.  grunt.initConfig({    pkg: grunt.file.readJSON('package.json'),    uglify: {      options: {        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
'      },      build: {        src: 'src/<%= pkg.name %>.js',        dest: 'build/<%= pkg.name %>.min.js'      }    }  });  // 加载包含 "uglify" 任务的插件。  grunt.loadNpmTasks('grunt-contrib-uglify');  // 默认被执行的任务列表。  grunt.registerTask('default', ['uglify']);};

前面已经向你展示了整个 Gruntfile,接下来将详细解释其中的每一部分。

"wrapper" 函数

每一份 Gruntfile (和grunt插件)都遵循同样的格式,你所书写的Grunt代码必须放在此函数内:

module.exports = function(grunt) {  // Do grunt-related things in here};

项目和任务配置

大部分的Grunt任务都依赖某些配置数据,这些数据被定义在一个object内,并传递给grunt.initConfig 方法。

在下面的案例中,grunt.file.readJSON('package.json') 将存储在package.json文件中的JSON元数据引入到grunt config中。 由于<% %>模板字符串可以引用任意的配置属性,因此可以通过这种方式来指定诸如文件路径和文件列表类型的配置数据,从而减少一些重复的工作。

你可以在这个配置对象中(传递给initConfig()方法的对象)存储任意的数据,只要它不与你任务配置所需的属性冲突,否则会被忽略。此外,由于这本身就是JavaScript,你不仅限于使用JSON;你可以在这里使用任意的有效的JS代码。如果有必要,你甚至可以以编程的方式生成配置。

与大多数task一样,grunt-contrib-uglify 插件中的uglify 任务要求它的配置被指定在一个同名属性中。在这里有一个例子, 我们指定了一个banner选项(用于在文件顶部生成一个注释),紧接着是一个单一的名为build的uglify目标,用于将一个js文件压缩为一个目标文件。

// Project configuration.grunt.initConfig({  pkg: grunt.file.readJSON('package.json'),  uglify: {    options: {      banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
'    },    build: {      src: 'src/<%= pkg.name %>.js',      dest: 'build/<%= pkg.name %>.min.js'    }  }});

加载 Grunt 插件和任务

像 concatenation、[minification]、grunt-contrib-uglify 和 linting这些常用的任务(task)都已经以grunt插件的形式被开发出来了。只要在 package.json 文件中被列为dependency(依赖)的包,并通过npm install安装之后,都可以在Gruntfile中以简单命令的形式使用:

// 加载能够提供"uglify"任务的插件。grunt.loadNpmTasks('grunt-contrib-uglify');

注意: grunt --help 命令将列出所有可用的任务。

自定义任务

通过定义 default 任务,可以让Grunt默认执行一个或多个任务。在下面的这个案例中,执行 grunt 命令时如果不指定一个任务的话,将会执行uglify任务。这和执行grunt uglify 或者 grunt default的效果一样。default任务列表数组中可以指定任意数目的任务(可以带参数)。

// Default task(s).grunt.registerTask('default', ['uglify']);

如果Grunt插件中的任务(task)不能满足你的项目需求,你还可以在Gruntfile中自定义任务(task)。例如,在下面的 Gruntfile 中自定义了一个default 任务,并且他甚至不依赖任务配置:

module.exports = function(grunt) {  // A very basic default task.  grunt.registerTask('default', 'Log some stuff.', function() {    grunt.log.write('Logging some stuff...').ok();  });};

特定于项目的任务不必在 Gruntfile 中定义。他们可以定义在外部.js 文件中,并通过grunt.loadTasks方法加载。

配置任务

这个指南解释了如何使用 Gruntfile 来为你的项目配置task。如果你还不知道 Gruntfile 是什么,请先阅读 快速入门 指南并看看这个 Gruntfile 实例

Grunt配置

Grunt的task配置都是在 Gruntfile 中的grunt.initConfig方法中指定的。此配置主要是以任务名称命名的属性,也可以包含其他任意数据。一旦这些代表任意数据的属性与任务所需要的属性相冲突,就将被忽略。

此外,由于这本身就是JavaScript,因此你不仅限于使用JSON;你可以在这里使用任何有效的JavaScript。必要的情况下,你甚至可以以编程的方式生成配置。

grunt.initConfig({  concat: {    // 这里是concat任务的配置信息。  },  uglify: {    // 这里是uglify任务的配置信息  },  // 任意数据。  my_property: 'whatever',  my_src_files: ['foo/*.js', 'bar/*.js'],});

任务配置和目标

当运行一个任务时,Grunt会自动查找配置对象中的同名属性。多任务(multi-task)可以通过任意命名的“目标(target)”来定义多个配置。在下面的案例中,concat任务有名为foo和bar两个目标,而uglify任务仅仅只有一个名为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.    },  },});

同时指定任务(task)和目标(target),例如grunt concat:foo或者grunt concat:bar,将只会处理指定目标(target)的配置,而运行grunt concat将遍历所有目标(target)并依次处理。注意,如果一个任务使用grunt.task.renameTask重命名过,Grunt将在配置对象中查找以新的任务名命名的属性。

options属性

在一个任务配置中,options属性可以用来指定覆盖内置属性的默认值。此外,每一个目标(target)中还可以拥有一个专门针对此目标(target)的options属性。目标(target)级的平options将会覆盖任务级的options。

options对象是可选的,如果不需要,可以忽略。

grunt.initConfig({  concat: {    options: {      // 这里是任务级的Options,覆盖默认值     },    foo: {      options: {        // "foo" target options may go here, overriding task-level options.      },    },    bar: {      // No options specified; this target will use task-level options.    },  },});

文件

由于大多的任务都是执行文件操作,Grunt有一个强大的抽象层用于声明任务应该操作哪些文件。这里有好几种定义src-dest(源文件-目标文件)文件映射的方式,均提供了不同程度的描述和控制操作方式。任何一种多任务(multi-task)都能理解下面的格式,所以你只需要选择满足你需求的格式就行。

所有的文件格式都支持src和dest属性,此外"Compact"[简洁]和"Files Array"[文件数组]格式还支持以下一些额外的属性:

  • filter 它通过接受任意一个有效的fs.Stats方法名或者一个函数来匹配src文件路径并根据匹配结果返回true或者false。
  • nonull 如果被设置为 true,未匹配的模式也将执行。结合Grunt的--verbore标志, 这个选项可以帮助用来调试文件路径的问题。
  • dot 它允许模式模式匹配句点开头的文件名,即使模式并不明确文件名开头部分是否有句点。
  • matchBase如果设置这个属性,缺少斜线的模式(意味着模式中不能使用斜线进行文件路径的匹配)将不会匹配包含在斜线中的文件名。 例如,a?b将匹配/xyz/123/acb但不匹配/xyz/acb/123。
  • expand 处理动态的src-dest文件映射,更多的信息请查看动态构建文件对象
  • 其他的属性将作为匹配项传递给底层的库。 请查看node-glob 和minimatch 文档以获取更多信息。

简洁格式

这种形式允许每个目标对应一个src-dest文件映射。通常情况下它用于只读任务,比如grunt-contrib-jshint,它就只需要一个单一的src属性,而不需要关联的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',    },  },});

文件对象格式

这种形式支持每个目标对应多个src-dest形式的文件映射,属性名就是目标文件,源文件就是它的值(源文件列表则使用数组格式声明)。可以使用这种方式指定数个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'],      },    },  },});

文件数组格式

这种形式支持每个目标对应多个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文件格式在多任务和目标出现之前是一个过渡形式,目标文件路径实际上就是目标名称。遗憾的是, 由于目标名称是文件路径,那么运行grunt task:target可能不合适。此外,你也不能指定一个目标级的options或者给每个src-dest文件映射指定额外属性。

此种格式已经不赞成使用,请尽量不要使用。

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',    },  },});

或者创建你自己的filter函数,根据文件是否匹配来返回true或者false。下面的例子将仅仅清理一个空目录:

grunt.initConfig({  clean: {    foo: {      src: ['tmp/**/*'],      filter: function(filepath) {        return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);      },    },  },});

通配符模式

通常分别指定所有源文件路径是不切实际的,因此Grunt通过内置支持node-glob 和 minimatch 库来匹配文件名(又叫作globbing)。

然这并不是一个综合的匹配模式方面的教程,你只需要知道如何在文件路径匹配过程中使用它们即可:

  • * 匹配任意数量的字符,但不匹配 /
  • ? 匹配单个字符,但不匹配 /
  • ** 匹配任意数量的字符,包括 /,只要它是路径中唯一的一部分
  • {} 允许使用一个逗号分割的“或”表达式列表
  • ! 在模式的开头用于排除一个匹配模式所匹配的任何文件

每个人都需要知道的是:foo/*.js将匹配位于foo/目录下的所有的.js结尾的文件;而foo/**/*js将匹配foo/目录以及其子目录中所有以.js结尾的文件。

此外, 为了简化原本复杂的通配符模式,Grunt允许指定一个数组形式的文件路径或者一个通配符模式。所有模式按顺序处理,模式处理的过程中,带有!前缀的模式所匹配的文件将不包含在结果集中。 而且其结果集中的每一项也是唯一的。

例如:

// 指定单个文件:{src: 'foo/this.js', dest: ...}// 指定一个文件数组:{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: ...}

更多关于通配符模式的语法,请查看node-glob 和 minimatch 的文档。

动态构建文件对象

当你希望处理大量的单个文件时,这里有一些附加的属性可以用来动态的构建一个文件列表。这些属性都可以用于Compact和Files Array文件映射格式。

expand 设置为true用于启用下面的选项:

  • cwd 所有src指定的匹配都将相对于此处指定的路径(但不包括此路径) 。
  • src 相对于cwd路径的匹配模式。
  • dest 目标文件路径前缀。
  • ext 对于生成的dest路径中所有实际存在文件,均使用这个属性值替换扩展名。
  • extDot 用于指定标记扩展名的英文点号的所在位置。可以赋值 'first' (扩展名从文件名中的第一个英文点号开始) 或 'last' (扩展名从最后一个英文点号开始),默认值为 'first' [添加于 0.4.3 版本]
  • flatten 从生成的dest路径中移除所有的路径部分。
  • rename 对每个匹配的src文件调用这个函数(在重命名后缀和移除路径之后)。dest和匹配的src路径将被作为参数传入,此函数应该返回一个新的dest值。 如果相同的dest返回不止一次,那么,每个返回此值的src来源都将被添加到一个数组中作为源列表。

在下面的例子中,uglify 任务中的static_mappings和dynamic_mappings两个目标具有相同的src-dest文件映射列表, 这是因为任务运行时Grunt会自动展开dynamic_mappings文件对象为4个单独的静态src-dest文件映射--假设这4个文件能够找到。

可以指定任意静态src-dest和动态的src-dest文件映射相互结合。

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        },      ],    },  },});

模板

使用<% %>分隔符指定的模板会在任务从它们的配置中读取相应的数据时将自动扩展扫描。模板会被递归的展开,直到配置中不再存在遗留的模板相关的信息(与模板匹配的)。

整个配置对象决定了属性上下文(模板中的属性)。此外,在模板中使用grunt以及它的方法都是有效的,例如: <%= grunt.template.today('yyyy-mm-dd') %>。

  • <%= prop.subprop %> 将会自动展开配置信息中的prop.subprop的值,不管是什么类型。像这样的模板不仅可以用来引用字符串值,还可以引用数组或者其他对象类型的值。
  • <% %> 执行任意内联的JavaScript代码。对于控制流或者循环来说是非常有用的。

下面以concat任务配置为例,运行grunt concat:sample时将通过banner中的/* abcde */连同foo/*.js+bar/*.js+bar/*.js匹配的所有文件来生成一个名为build/abcde.js的文件。

grunt.initConfig({  concat: {    sample: {      options: {        banner: '/* <%= baz %> */
',   // '/* abcde */
'      },      src: ['<%= qux %>', 'baz/*.js'],  // [['foo/*.js', 'bar/*.js'], 'baz/*.js']      dest: 'build/<%= baz %>.js',      // 'build/abcde.js'    },  },  //用于任务配置模板的任意属性  foo: 'c',  bar: 'b<%= foo %>d', // 'bcd'  baz: 'a<%= bar %>e', // 'abcde'  qux: ['foo/*.js', 'bar/*.js'],});

导入外部数据

在下面的Gruntfile中,项目的元数据是从package.json文件中导入到Grunt配置中的,并且grunt-contrib-uglify 插件中的 uglify 任务被配置用于压缩一个源文件以及使用该元数据动态的生成一个banner注释。

Grunt有grunt.file.readJSON和grunt.file.readYAML两个方法分别用于引入JSON和YAML数据。

grunt.initConfig({  pkg: grunt.file.readJSON('package.json'),  uglify: {    options: {      banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */
'    },    dist: {      src: 'src/<%= pkg.name %>.js',      dest: 'dist/<%= pkg.name %>.min.js'    }  }});

Gruntfile 实例

下面就针对一个 Gruntfile 案例做简单分析,也可以作为一个实例使用:

module.exports = function(grunt) {  grunt.initConfig({    jshint: {      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],      options: {        globals: {          jQuery: true        }      }    },    watch: {      files: ['<%= jshint.files %>'],      tasks: ['jshint']    }  });  grunt.loadNpmTasks('grunt-contrib-jshint');  grunt.loadNpmTasks('grunt-contrib-watch');  grunt.registerTask('default', ['jshint']);};

在页面底部是这个 Gruntfile 实例的完整内容,如果你按顺序阅读本文的话,可以跟随我们一步步分析这个文件中的每一部分。我们会用到以下5个 Grunt 插件:

第一部分是"wrapper" 函数,它包含了整个Grunt配置信息。

module.exports = function(grunt) {}

在这个函数中,我们可以初始化 configuration 对象:

grunt.initConfig({});

接下来可以从package.json 文件读入项目配置信息,并存入pkg 属性内。这样就可以让我们访问到package.json文件中列出的属性了,如下:

pkg: grunt.file.readJSON('package.json')

到目前为止我们就可以看到如下配置:

module.exports = function(grunt) {  grunt.initConfig({    pkg: grunt.file.readJSON('package.json')  });};

现在我们就可以为我们的每个任务来定义相应的配置(逐个定义我们为项目定义的任务配置),然后每个任务的配置对象作为Grunt配置对象(即grunt.initConfig({})所接受的配置对象)的属性,并且这个属性名称与任务名相同。因此"concat"任务就是我们的配置对象中的"concat"键(属性)。下面便是我的"concat"任务的配置对象。

concat: {  options: {    // 定义一个用于插入合并输出文件之间的字符    separator: ';'  },  dist: {    // 将要被合并的文件    src: ['src/**/*.js'],    // 合并后的JS文件的存放位置    dest: 'dist/<%= pkg.name %>.js'  }}

注意我是如何引用JSON文件(也就是我们在配置对象顶部引入的配置文件)中的name属性的。这里我使用pkg.name来访问我们刚才引入并存储在pkg属性中的package.json文件信息,它会被解析为一个JavaScript对象。Grunt自带的有一个简单的模板引擎用于输出配置对象(这里是指package.json中的配置对象)属性值,这里我让concat任务将所有存在于src/目录下以.js结尾的文件合并起来,然后存储在dist目录中,并以项目名来命名。

现在我们来配置uglify插件,它的作用是压缩(minify)JavaScript文件:

uglify: {  options: {    // 此处定义的banner注释将插入到输出文件的顶部    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */
'  },  dist: {    files: {      'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']    }  }}

这里我们让uglify在dist/目录中创建了一个包含压缩结果的JavaScript文件。注意这里我使用了<%= concat.dist.dest>,因此uglify会自动压缩concat任务中生成的文件。

QUnit插件的设置非常简单。 你只需要给它提供用于测试运行的文件的位置,注意这里的QUnit是运行在HTML文件上的。

qunit: {  files: ['test/**/*.html']},

JSHint插件的配置也很简单:

jshint: {  // define the files to lint  files: ['gruntfile.js', 'src/**/*.js', 'test/**/*.js'],  // configure JSHint (documented at http://www.jshint.com/docs/)  options: {      // more options here if you want to override JSHint defaults    globals: {      jQuery: true,      console: true,      module: true    }  }}

JSHint只需要一个文件数组(也就是你需要检测的文件数组), 然后是一个options对象(这个对象用于重写JSHint提供的默认检测规则)。你可以到JSHint官方文档站点中查看完整的文档。如果你乐于使用JSHint提供的默认配置,那么在Gruntfile中就不需要重新定义它们了.

最后,我们来看看watch插件:

watch: {  files: ['<%= jshint.files %>'],  tasks: ['jshint', 'qunit']}

你可以在命令行使用grunt watch来运行这个任务。当它检测到任何你所指定的文件(在这里我使用了JSHint任务中需要检测的相同的文件)发生变化时,它就会按照你所指定的顺序执行指定的任务(在这里我指定了jshint和qunit任务)。

最后, 我们还要加载所需要的Grunt插件。 它们应该已经全部通过npm安装好了。

grunt.loadNpmTasks('grunt-contrib-uglify');grunt.loadNpmTasks('grunt-contrib-jshint');grunt.loadNpmTasks('grunt-contrib-qunit');grunt.loadNpmTasks('grunt-contrib-watch');grunt.loadNpmTasks('grunt-contrib-concat');

最后设置了一些task。最重要的是default任务:

// 在命令行上输入"grunt test",test task就会被执行。grunt.registerTask('test', ['jshint', 'qunit']);// 只需在命令行上输入"grunt",就会执行default taskgrunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

下面便是最终完成的 Gruntfile 文件:

module.exports = function(grunt) {  grunt.initConfig({    pkg: grunt.file.readJSON('package.json'),    concat: {      options: {        separator: ';'      },      dist: {        src: ['src/**/*.js'],        dest: 'dist/<%= pkg.name %>.js'      }    },    uglify: {      options: {        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */
'      },      dist: {        files: {          'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']        }      }    },    qunit: {      files: ['test/**/*.html']    },    jshint: {      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],      options: {        //这里是覆盖JSHint默认配置的选项        globals: {          jQuery: true,          console: true,          module: true,          document: true        }      }    },    watch: {      files: ['<%= jshint.files %>'],      tasks: ['jshint', 'qunit']    }  });  grunt.loadNpmTasks('grunt-contrib-uglify');  grunt.loadNpmTasks('grunt-contrib-jshint');  grunt.loadNpmTasks('grunt-contrib-qunit');  grunt.loadNpmTasks('grunt-contrib-watch');  grunt.loadNpmTasks('grunt-contrib-concat');  grunt.registerTask('test', ['jshint', 'qunit']);  grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);};

创建任务

任务是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重命名过,Grunt将会自动在配置对象中查找新任务名称属性。

大部分的contrib任务(主要是指官方提供的任务),包括grunt-contrib-jshint插件的jshint任务,以及grunt-contrib-concat插件的concat任务都是多任务形式的。

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 中可以查看更多案例。

CLI 参数 / 环境

通过 process.env 来访问环境变量

请参考 使用命令行工具章节,查看完整的的命令行选项列表。

为什么我的异步task没有完成?

如果发生这种情况,可能是由于你忘记调用 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 文档

创建插件

  1. 通过 npm install -g grunt-init 命令安装 grunt-init 。
  2. 通过git clone git://github.com/gruntjs/grunt-init-gruntplugin.git ~/.grunt-init/gruntplugin 命令安装grunt插件模版。
  3. 在一个空的目录中执行 grunt-init gruntplugin 。
  4. 执行 npm install 命令以准备开发环境。
  5. 为你的插件书写代码。
  6. 执行 npm publish 命令将你创建的 Grunt 插件提发布npm!

注意

命名你的task

"grunt-contrib" 命名空间保留给 Grunt 团队维护的task使用,请给你自己的task起一个合适名字,并且避免使用被保留的命名空间。

调试

Grunt默认隐藏了error stack traces,但是可以通过 --stack 参数启用,方便你调试自己的task。如果你希望 Grunt 在出现错误时总是能记录下stack trace,可以在你的shell中创建一个命令别名(alias)。例如,在bash中,可以通过 alias grunt='grunt --stack' 命令创建一个别名。

存储任务文件

只在项目根目录中的 .grunt/[npm-module-name] 目录中存储数据文件,并在适当的时候将其清除。对于临时文件这并不是一个好的解决方案, 建议使用后面列出的几个常用npm模块(例如 temporarytmp)来调用操作系统级别的临时目录功能。

避免改变当前工作目录:process.cwd()

默认情况下,包含gruntfile文件的目录被设置为当前工作目录。用户可以在自己的gruntfile中通过执行grunt.file.setBase() 改变改变当前工作目录,但是插件不应该改变它。

path.resolve('foo') 可以被用来获取'foo' 相对于 Gruntfile 所在目录的绝对路径。

使用命令行工具

安装命令行工具

执行 sudo npm install -g grunt-cli 。

grunt命令行接口提供了一系列选项。你可以在你的终端中使用grunt -h查看这个选项。

--help, -h

显示帮助信息。

--base, -b

指定一个基本路径。默认情况下,所有文件路径都是相对于Gruntfile的。

还可以调用 grunt.file.setBase(...)

--no-color

禁用彩色输出。

--gruntfile

指定 Gruntfile 文件。

默认情况下,grunt会从当前目录或者父目录中寻找最近的Gruntfile.js或者Gruntfile.coffee文件。

--debug, -d

对支持调试的任务启用调试模式。

--stack

因警告或者致命错误退出时打印堆栈跟踪信息。

--force, -f

一种强制跳过警告信息的方式。

如果像从警告中得到提示,就不要使用这个选项,可以根据提示信息修正代码。

--tasks

指定一个包含可加载的任务和“额外”文件的目录。

还可以调用 grunt.loadTasks(...)

--npm

在通过npm安装的插件中检查可加载的任何以及额外文件。

还可以调用 grunt.loadNpmTasks(...)

--no-write

禁用写文件操作(可用于演示)。

--verbose, -v

冗长模式(Verbose mode)。会输出很多的信息。

--version, -V

打印grunt版本。结合 --verbose 一起使用可以获取更多信息。

--completion

输出shell的自动补全规则。更多信息参考grunt-cli相关的文档。

grunt

Grunt通过grunt对象暴露所有方法和属性,并将此对象赋予module.exports函数,这些方法和属性都将传递到你的Gruntfile、Grunt插件或者task文件中。

以下所有的方法几乎都是在别处定义的,但是为了方便使用,也在grunt对象中做了定义。详细的解释和案例请参阅各个api单独的文档。

Config

grunt.initConfig

此方法是 grunt.config.init 方法的别名(alias)。

创建task

grunt.registerTask

此方法是 grunt.task.registerTask 方法的别名(alias)。

grunt.registerMultiTask

此方法是 grunt.task.registerMultiTask 方法的别名(alias)。

grunt.renameTask

此方法是 grunt.task.renameTask 方法的别名(alias)。

Loading Externally-Defined Tasks

grunt.loadTasks

此方法是 grunt.task.loadTasks 方法的别名(alias)。

grunt.loadNpmTasks

此方法是 grunt.task.loadNpmTasks 方法的别名(alias)。

警告和致命错误

grunt.warn

此方法是 grunt.fail.warn 方法的别名(alias)。

grunt.fatal

此方法是 grunt.fail.fatal 方法的别名(alias)。

命令行参数

grunt.option

检索命令行参数的值,例如debug。注意对于每个命令行参数,都可以做相反的测试,例如no-debug

grunt.option(optionName)

杂项

grunt.package

package.json 中存储的元数据,其类型是对象。

grunt.package

grunt.version

当前 Grunt 的版本,类型是字符串。它仅仅是grunt.package.version属性的缩写。

grunt.version

grunt.config

从 Gruntfile 中获取针对当前项目的配置数据。

注意,任何标记为 ☃ (unicode snowman) 的方法也是可以直接通过 grunt 对象访问的;任何标记为 ☆ (white star) 的方法都可以在task内部通过 this 对象访问的。请知晓。

初始化配置数据

注意,下面列出的方法也可以通过 grunt 对象访问,访问形式为 grunt.initConfig

grunt.config.init

为当前项目初始化一个配置对象。其中传入的 configObject 参数可以用在后续的task中,可以通过grunt.config 方法访问。几乎每个项目的 Gruntfile 都会调用此方法。

grunt.config.init(configObject)

注意,任何 <% %> 模板字符串只会在取到配置数据后才被处理。

下面的案例展示了针对 grunt-contrib-jshint插件 中的 jshint task的配置数据:

grunt.config.init({  jshint: {    all: ['lib/*.js', 'test/*.js', 'Gruntfile.js']  }});

查看 Getting started 指南可以获取更多的配置案例。

此方法还可以以 grunt.initConfig 的形式访问。

获取配置数据

The following methods allow Grunt configuration data to be accessed either via dot-delimited string like'pkg.author.name' or via array of property name parts like ['pkg', 'author', 'name'].

Note that if a specified property name contains a . dot, it must be escaped with a literal backslash, eg.'concat.dist/built.js'. If an array of parts is specified, Grunt will handle the escaping internally with the grunt.config.escape method.

grunt.config

从项目的 Grunt 配置中获取或者设置一个值。这个方法作为其他方法的别名;如果传递两个参数,grunt.config.set被调用,另一方面grunt.config.get也被调用。Get or set a value from the project's grunt configuration. This method serves as an alias to other methods; if two arguments are passed, grunt.config.set is called, otherwise grunt.config.get is called.

grunt.config([prop [, value]])

grunt.config.get

Get a value from the project's Grunt configuration. If prop is specified, that property's value is returned, ornull if that property is not defined. If prop isn't specified, a copy of the entire config object is returned. Templates strings will be recursively processed using the grunt.config.process method.

grunt.config.get([prop])

grunt.config.process

Process a value, recursively expanding <% %> templates (via the grunt.template.process method) in the context of the Grunt config, as they are encountered. this method is called automatically bygrunt.config.get but not by grunt.config.getRaw.

grunt.config.process(value)

If any retrieved value is entirely a single '<%= foo %>' or '<%= foo.bar %>' template string, and the specified foo or foo.bar property is a non-string (and not null or undefined) value, it will be expanded to the actual value. That, combined with grunt's task system automatically flattening arrays, can be extremely useful.

grunt.config.getRaw

Get a raw value from the project's Grunt configuration, without processing <% %> template strings. Ifprop is specified, that property's value is returned, or null if that property is not defined. If prop isn't specified, a copy of the entire config object is returned.

grunt.config.getRaw([prop])

grunt.config.set

给当前项目的 Grunt 配置中的某个属性设置一个值。

grunt.config.set(prop, value)

注意,任何 <% %> 模板字符串只会在取到配置数据后才被处理。

grunt.config.escape

忽略给定的propString中的.点号。这应该用于包含点号的属性名。Escape . dots in the givenpropString. This should be used for property names that contain dots.

grunt.config.escape(propString)

grunt.config.merge

Added in 0.4.5

Recursively merges properties of the specified configObject into the current project configuration.

grunt.config.merge(configObject)

You can use this method to append configuration options, targets, etc., to already defined tasks, for example:

grunt.config.merge({  watch: {    files: ["path/to/files"],    tasks: ["task"]  }});

Requiring Config Data

注意,下面列出的方法都可以在task内部通过 this 对象访问,访问形式为 this.requiresConfig

grunt.config.requires

如果需要的配置属性有一个或多个不存在、值为null 或 undefined,当前task将失败。此方法可以指定一个或多个字符串、配置属性数组作为参数。

grunt.config.requires(prop [, prop [, ...]])

此方法在task内部以 this.requiresConfig 形式调用。

grunt.event

在这个页面中仅仅列出了最重要的方法,完整的 EventEmitter2 API 在 grunt.event 对象中都有定义。事件命名空间可以使用 .(英文句号)做分隔,并且可以使用命名空间通配符。

注意:Grunt目前并不发出任何事件,但是在你自己的task中仍然是有用的。

grunt.event.on

为指定的事件添加一个监听器,并将此监听器放倒监听器数组的尾部。

grunt.event.on(event, listener)

grunt.event.once

为指定的事件添加一个执行 一次 的监听器。次监听器只在事件头一次被触发后才会被调用,并且执行完之后被移除。

grunt.event.once(event, listener)

grunt.event.many

为指定的事件添加一个监听器,并在被移除之前执行 n 次 。

grunt.event.many(event, timesToListen, listener)

grunt.event.off

从监听器数组中移除所有监听某个指定事件的监听器。

grunt.event.off(event, listener)

grunt.event.removeAllListeners

移除所有的监听器,或者某个指定事件的所有监听器。

grunt.event.removeAllListeners([event])

grunt.event.emit

依次执行每一个可能监听此事件名的监听器,并将参数列表传给每个事件监听器。

grunt.event.emit(event, [arg1], [arg2], [...])

grunt.file

这里提供了很多用于读写文件、遍历文件系统和通过模式匹配查找文件的方法。其中很多方法都是Node.js中的文件操作函数的封装,但是提供了额外的错误处理、日志记录和字符编码转换。

注意:所有的文件路径都是参照 Gruntfile 文件的相对路径,除非通过 grunt.file.setBase 函数或在命令行中指定 --base 参数改变当前工作目录。

字符编码

grunt.file.defaultEncoding

设置此属性可以改变所有 grunt.file 方法的默认编码。默认是 'utf8'。如果必须改变这个值,建议你在Gruntfile文件中尽可能早改变。

grunt.file.defaultEncoding = 'utf8';

grunt.file.preserveBOM

添加于 0.4.2 版本

是否在 file.read 时保留字节顺序标记(BOM)。

grunt.file.preserveBOM = false;

读写文件

grunt.file.read

读取并返回文件的内容。返回值为一个字符串,如果 options.encoding 为 null ,则返回一个 Buffer

grunt.file.read(filepath [, options])

options 对象可以设置以下属性:

var options = {  // If an encoding is not specified, default to grunt.file.defaultEncoding.  // If specified as null, returns a non-decoded Buffer instead of a string.  encoding: encodingName};

grunt.file.readJSON

读取一个文件的内容,将其按照JSON格式解析,返回结果。参见 grunt.file.read 获取其所支持的参数列表。

grunt.file.readJSON(filepath [, options])

grunt.file.readYAML

读取一个文件的内容,将其按照YAML格式解析,返回结果。参见 grunt.file.read 获取其所支持的参数列表。

grunt.file.readYAML(filepath [, options])

grunt.file.write

将指定的内容写入文件中,如果需要,将创建文件路径中所有不存在的目录。字符串将按照指定的字符编码进行编码,Buffers 将会按照指定的方式写入磁盘。

如果指定了 --no-write 命令行参数,将不会真正写入文件。

grunt.file.write(filepath, contents [, options])

options 对象可设置以下属性:

var options = {  // If an encoding is not specified, default to grunt.file.defaultEncoding.  // If `contents` is a Buffer, encoding is ignored.  encoding: encodingName};

grunt.file.copy

将原文件拷贝到指定路径,如果需要,将创建文件路径中所有不存在的目录

如果指定了 --no-write 命令行参数,将不会真正写入文件。

grunt.file.copy(srcpath, destpath [, options])

options 对象可设置以下属性:

var options = {  // If an encoding is not specified, default to grunt.file.defaultEncoding.  // If null, the `process` function will receive a Buffer instead of String.  encoding: encodingName,  // The source file contents, source file path, and destination file path   // are passed into this function, whose return value will be used as the  // destination file's contents. If this function returns `false`, the file  // copy will be aborted.  process: processFunction,  // These optional globbing patterns will be matched against the filepath  // (not the filename) using grunt.file.isMatch. If any specified globbing  // pattern matches, the file won't be processed via the `process` function.  // If `true` is specified, processing will be prevented.  noProcess: globbingPatterns};

grunt.file.delete

删除指定的文件。文件和目录会被依次递归删除。

Will not delete the current working directory or files outside the current working directory unless the--force command-line option is specified.

如果指定了 --no-write 命令行参数,那么,文件路径将不会真的被删除。

grunt.file.delete(filepath [, options])

options 对象只可以设置以下属性:

var options = {  // Enable deleting outside the current working directory. This option may  // be overridden by the --force command-line option.  force: true};

目录操作

grunt.file.mkdir

工作方式类似 mkdir -p。创建一个目录和所有的中间目录。如果没有指定 mode ,默认是0777 & (~process.umask()).

如果没有 --no-write 命令行参数,目录不会被真正创建。

grunt.file.mkdir(dirpath [, mode])

grunt.file.recurse

递归遍历整个目录,对每个文件都执行 callback 函数。

grunt.file.recurse(rootdir, callback)

callback 函数接收以下参数:

function callback(abspath, rootdir, subdir, filename) {  // The full path to the current file, which is nothing more than  // the rootdir + subdir + filename arguments, joined.  abspath  // The root director, as originally specified.  rootdir  // The current file's directory, relative to rootdir.  subdir  // The filename of the current file, without any directory parts.  filename}

模式匹配

有时单独指定所有原始文件路径是不现实的,因此,Grunt通过内置的node-glob 库支持文件名 expansion (或者叫做 globbing) 。

参见 配置任务 指南中的 "Globbing patterns" 章节以获取 globbing pattern 实例。

grunt.file.expand

返回包含匹配给定通配符模式的文件或者目录路径的特殊数组。这个方法接收一个逗号分割的匹配模式或者一个匹配模式数组。如果路径匹配模式以!开头,它会从返回的数组排除所匹配的项。模式是按指定的顺序进行处理的, 因此包含和排除文件的顺序是很重要的。

grunt.file.expand([options, ] patterns)

文件路径都是参照 Gruntfile 文件的相对路径,除非通过 grunt.file.setBase 或 --base 命令行参数修改了当前工作目录。

options 对象支持所有 minimatch library 的参数,也支持额外的一些,如下:

  • filter E接受一个有效的 fs.Stats 方法名 或者一个已经通过了src文件路径匹配的函数,这个函数会返回truefalse
  • nonull 会保留src匹配模式,即使文件匹配失败。结合Grunt的-verbose标志,这个选项有助于文件路径问题的调试。
  • matchBase 不带斜线的模式只会匹配基本的名称部分。例如,这会使*.js就像**/*.js一样。
  • cwd 会让模式相对于当前路径进行模式匹配,所有返回的文件路径也是相对于当前路径的。

grunt.file.expandMapping

返回一个src-dest文件映射对象的数组。通过所指定的模式来匹配每一个源文件,然后将匹配的文件路径加入指定的dest中(dest存放匹配的文件路径)。这个文件路径会按照指定的选项加工或者重命名过。 查看grunt.file.expand方法文档可以了解如何指定patternsoptions

grunt.file.expandMapping(patterns, dest [, options])

注意:这个方法可以用于以编程的方式针对多任务的情况生成一个files数组,它会优先使用在配置任务指南中"动态构建文件对象"一节所描述的语法。

除了支持那些grunt.file.expand方法之外,options对象还支持下面这些属性:

var options = {  // The directory from which patterns are matched. Any string specified as  // cwd is effectively stripped from the beginning of all matched paths.  cwd: String,  // Remove the path component from all matched src files. The src file path  // is still joined to the specified dest.  flatten: Boolean,  // Remove anything after (and including) either the first or last "." in the   // destination path (indicated by options.extDot), then append this value.  ext: String,  // *Added in 0.4.3*  // Indicates where the period demarcating the extension is located. Can take:  // - 'first' (extension begins after the first period in the file name)   // - 'last' (extension begins after the last period)  // Default: 'first'  extDot: String,  // If specified, this function will be responsible for returning the final  // dest filepath. By default, it joins dest and matchedSrcPath like so:  rename: function(dest, matchedSrcPath, options) {    return path.join(dest, matchedSrcPath);  }};

grunt.file.match

针对一个或者多个文件路径来匹配一个或者多个匹配模式。返回一个特殊的数组,这个数组包含与指定的通配符模式任意匹配的所有文件路径。patternsfilepaths参数可以是一个单一的字符串或者也可以是一个字符串数组.如果匹配模式以!开头,就会从返回的数组从排除模式匹配的路径。模式会按指定的顺序进行处理,因此包含和排除文件的顺序是重要的。

grunt.file.match([options, ] patterns, filepaths)

options对象也支持minimatch库提供的所有选项。例如:如果options.matchBase为true,即使模式中不带斜线,这个模式也会匹配包含斜线的基本名称。例如:*.js模式将匹配path/to/file.js文件路径。

grunt.file.isMatch

这个方法与grunt.file.match方法包含同样的签名和逻辑,但是如果它匹配任意文件,就会简单的返回ture,否则返回false

判断文件类型

grunt.file.exists

检测给定的路径是否存在,返回boolean类型的值。

和Node.js 中的 path.join 方法一样,此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.exists(path1 [, path2 [, ...]])

grunt.file.isLink

给定的路径是否是符号链接,返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isLink(path1 [, path2 [, ...]])

如果路径不存在则返回false。

grunt.file.isDir

指定的路径是否是一个目录?返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isDir(path1 [, path2 [, ...]])

如果路径不存在它也会返回false。

grunt.file.isFile

指定的路径是否是一个文件? 返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isFile(path1 [, path2 [, ...]])

如果路径不存在将返回false。

路径

grunt.file.isPathAbsolute

指定的文件路径是否是绝对路径? 返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isPathAbsolute(path1 [, path2 [, ...]])

grunt.file.arePathsEquivalent

所有给出的路径是否都是同一个路径?返回boolean类型的值。

grunt.file.arePathsEquivalent(path1 [, path2 [, ...]])

grunt.file.doesPathContain

所有descendant路径是否全部包含在指定的ancestor路径中?返回boolean类型的值。

注意:不需要检查路径是否真的存在。

grunt.file.doesPathContain(ancestorPath, descendantPath1 [, descendantPath2 [, ...]])

grunt.file.isPathCwd

指定的文件路径是否是CWD?返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isPathCwd(path1 [, path2 [, ...]])

grunt.file.isPathInCwd

指定的文件路径是否在在CWD中?注意:CWD不在CWD 。返回boolean类型的值。

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

grunt.file.isPathInCwd(path1 [, path2 [, ...]])

grunt.file.setBase

改变Grunt的当前工作目录(CWD)。默认情况下,所有文件路径都是参照 Gruntfile 文件的相对路径。此函数和 --base 命令行参数的工作方式一致。

grunt.file.setBase(path1 [, path2 [, ...]])

和 Node.js 中的 path.join 方法一样,此方法此方法将所有参数连接在一起,并对结果做规范化。

外部工具库

不建议使用

下面列出的所有外部工具库已经不再建议使用了。

请使用 npm 管理项目中对第三方工具库的依赖。

例如,如果你需要使用 Lo-Dash,首先通过 npm install lodash 安装,然后在 Gruntfile 文件中使用即可: var _ = require('lodash');

grunt.file.glob

不建议使用

glob - File globbing utility.

grunt.file.minimatch

不建议使用

minimatch - File pattern matching utility.

grunt.file.findup

不建议使用

findup-sync - Search upwards for matching file patterns.

grunt.log

向控制台输出信息。

参见 log lib source 以获取更多信息。

The log API

Grunt的输出应当看上去一致、美观。因此, 就有了这些log方法和一些有用的模式。所有用于输出日志的方法都可以链式调用。

注意:只有在命令行中指定 --verbose 选项时,所有 grunt.verbose 中的方法才会输出日志,并且完全像 grunt.log 中的方法一样工作。

grunt.log.write / grunt.verbose.write

输出指定的 msg 字符串日志,结尾不带换行符(newline)。

grunt.log.write(msg)

grunt.log.writeln / grunt.verbose.writeln

输出指定的 msg 字符串日志,结尾带换行符(newline)。

grunt.log.writeln([msg])

grunt.log.error / grunt.verbose.error

如果省略msg 字符串,将会以红色字体输出ERROR,否则输出>> msg,并且尾部带有换行符。

grunt.log.error([msg])

grunt.log.errorlns / grunt.verbose.errorlns

使用grunt.log.error记录一个错误日志,使用grunt.log.wraptext可以将日志以每行80个字符的形式输出。

grunt.log.errorlns(msg)

grunt.log.ok / grunt.verbose.ok

如果省略msg字符串,将会以绿色字体输出OK, 否则输出>> msg,并且尾部带有换行符。

grunt.log.ok([msg])

grunt.log.oklns / grunt.verbose.oklns

使用grunt.log.ok记录一条ok消息,使用grunt.log.wraptext可以将日志以每行80个字符的形式输出。

grunt.log.oklns(msg)

grunt.log.subhead / grunt.verbose.subhead

记录指定的msg字符串并加粗,尾部带有换行符。

grunt.log.subhead(msg)

grunt.log.writeflags / grunt.verbose.writeflags

记录obj的属性列表(用于调试标志最好)。

grunt.log.writeflags(obj, prefix)

grunt.log.debug / grunt.verbose.debug

记录一条调试信息,但是,仅当在命令行中指定 --debug选项时才会输出。

grunt.log.debug(msg)

Verbose 和 Notverbose

所有grunt.verbose下可用的日志记录方法的工作都酷似它们所对应的grunt.log方法,但是它们只在指定--verbose命令行选项的情况下才一样。还有一个对应"notverbose"适用于grunt.log.notverbosegrunt.log.verbose.or。实际上,.or属性也可以用于在verbosenotverbose两者之间有效的进行切换。

grunt.verbose / grunt.log.verbose

这个对象包含grunt.log下的所有方法,但是只在指定--verbose命令行选项情况下它才会输出日志信息。

grunt.verbose

grunt.verbose.or / grunt.log.notverbose

这个对象也包含grunt.log下的所有方法,但是只在不指定--verbose命令行选项情况下它才会输出日志信息。

grunt.verbose.or

工具方法

这些方法实际上不记录日志,它们只返回字符串,返回的字符串可以用于其他方法。

grunt.log.wordlist

Returns a comma-separated list of arr array items. arr 数组中的条目将会以逗号分割的形式返回。

grunt.log.wordlist(arr [, options])

options 对象拥有以下属性和默认值:

var options = {  // The separator string (can be colored).  separator: ', ',  // The array item color (specify false to not colorize).  color: 'cyan',};

grunt.log.uncolor

从字符串中移除所有颜色信息,使其适合检测其 .length 或写入日志文件。、

grunt.log.uncolor(str)

grunt.log.wraptext

以 width 个字符为一组将 text 字符串进行分解并添加   字符,除非绝对必要,否则将尽量确保不会从中间截断单词。

grunt.log.wraptext(width, text)

grunt.log.table

以 width 个字符为一组将 text 字符串进行分解。Wrap texts array of strings to columns widthscharacters wide. A wrapper for the grunt.log.wraptext method that can be used to generate output in columns.

grunt.log.table(widths, texts)

案例

通常的模式是,只有在 --verbose 模式或发生错误时才输出日志,如下所示:

grunt.registerTask('something', 'Do something interesting.', function(arg) {  var msg = 'Doing something...';  grunt.verbose.write(msg);  try {    doSomethingThatThrowsAnExceptionOnError(arg);    // Success!    grunt.verbose.ok();  } catch(e) {    // Something went wrong.    grunt.verbose.or.write(msg).error().error(e.message);    grunt.fail.warn('Something went wrong.');  }});

解释以上代码:

  1. grunt.verbose.write(msg); 只有在 --verbose 模式时才会输出日志信息(没有换行符)。
  2. grunt.verbose.ok(); 以绿色输出日志信息,末尾输出换行符。
  3. grunt.verbose.or.write(msg).error().error(e.message); 做了以下几件事:
    1. grunt.verbose.or.write(msg) 如果不在 --verbose 模式则输出日志信息,然后返回notverbose 对象。
    2. .error() 以红色输出ERROR日志,结尾输出换行符,然后返回 notverbose 对象。
    3. .error(e.message); 输出实际的错误信息(并返回 notverbose 对象)。
  4. grunt.fail.warn('Something went wrong.'); 以嫩黄色输出警告信息。除非在命令行指定了--force 选项,否则输出退出码1,然后退出 Grunt。

查看 grunt-contrib-* 任务的源码 以获取更多案例。

grunt.option

Grunt的option API被用来在多个任务之间共享参数、访问命令行中设置的参数。

一个简单的案例就是为一个目标(target)指定一个用于区别开发期还是过渡期的标志。在命令行中:grunt deploy --target=staging 会让grunt.option('target')返回"staging"

下面这个 Gruntfile 案例展示了如何使用 target 选项:

grunt.initConfig({  compass: {    dev: {      options: {        /* ... */        outputStyle: 'expanded'      },    },    staging: {      options: {        /* ... */        outputStyle: 'compressed'      },    },  },});var target = grunt.option('target') || 'dev';grunt.registerTask('deploy', ['compass:' + target]);

当你执行 grunt deploy 时,你的样式表将默认为dev目标并且输出易于阅读的CSS格式代码。如果你运行 grunt deploy --target=staging ,staging目标会被执行,输出压缩之后的CSS。

grunt.option 还可以在task中使用,如下:

grunt.registerTask('upload', 'Upload code to specified target.', function(n) {  var target = grunt.option('target');  // do something useful with target here});grunt.registerTask('deploy', ['validate', 'upload']);

注意,boolean参数可以仅指定key,而省略value。例如,在命令行执行 grunt deploy --staging 将会使grunt.option('staging') 返回 true

grunt.option

获取或设置一个选项。

grunt.option(key[, val])

boolean类型的选项可以通过在 key 前添加 no- 来取消。案例如下:

grunt.option('staging', false);var isDev = grunt.option('no-staging');// isDev === true

grunt.option.init

初始化 grunt.option。如果省略 initObject ,option将被初始化为一个空对象,否则将被设置为initObject

grunt.option.init([initObject])

grunt.option.flags

将所有参数作为命令行参数数组返回。

grunt.option.flags()

grunt.task

注册、执行和加载外部任务。

参见 task lib source 和 task util lib source 获取更多信息。

The task API

当一个任务正在执行时,Grunt 通过this 对象向此任务函数暴露了很多任务特定的属性和方法。参见 深入任务内幕指南,这里可以找到完整的属性和方法列表。

很多属性和方法都可以通过 this 对象访问到。

注意,任何标记为的 ☃ (unicode snowman) 方法也可以直接通过 grunt 对象直接访问到。参见 API首页以获取更多信息。

创建任务

grunt.task.registerTask

注册 "别名任务" 或 任务函数。此方法支持以下两种类型:

别名任务

如果指定了一个任务列表,那么,新注册的任务将会是这一个或多个任务的别名(alias)。当此"别名任务"执行时,taskList中的所有任务都将按指定的顺序依次执行。taskList 参数必须是一个任务数组。

grunt.task.registerTask(taskName, taskList)

下面这个案例展示的是定义一个"default" 任务,当执行 Grunt 且不通过参数指定任务时, "jshint"、 "qunit"、"concat" 和 "uglify" 任务将自动执行:

task.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

还可以指定任务的参数。下面的这个案例中,别名"dist"执行了 "concat" 和 "uglify" 这两个任务,并且都指定了"dist" 参数:

task.registerTask('dist', ['concat:dist', 'uglify:dist']);

任务函数

如果传入descriptiontaskFunction,每当任务运行时,指定的函数(taskFunction)都会被执行。此外,当执行 grunt --help时,前面指定的描述(description)就会显示出来。特定任务的属性和方法在任务函数内部通过this对象的属性即可访问。如果任务函数返回false表示任务失败。

注意,grunt.task.registerMultiTask方法将稍候介绍,它可以被用于定义一种特殊类型的任务,即"复合任务"。

grunt.task.registerTask(taskName, description, taskFunction)

下面这个案例中,当 Grunt 运行grunt foo:testing:123时,日志输出foo, testing 123。如果运行这个任务时不带参数,如grunt foo,日志输出foo, no args

grunt.task.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调用。

grunt.task.registerMultiTask

注册一个 "复合任务(multi task)"。 复合任务是指在不指定目标(target)时,将依次执行其所包含的所有已命名的子属性(sub-properties) (也就是 目标) 。除了默认的属性和方法外,还可以通过this对象访问复合任务独有的属性。

大多数的contrib任务,包括 jshint taskconcat task 和 uglify task 都是复合任务。

grunt.task.registerMultiTask(taskName, description, taskFunction)

给定以下配置信息,当执行grunt log:foo时,下面的复合任务将输出日志foo: 1,2,3;当执行grunt log:bar时,将输出日志bar: hello world。如果只是执行grunt log,那么,将先输出日志foo: 1,2,3,然后是bar: hello world,最后是baz: false

grunt.initConfig({  log: {    foo: [1, 2, 3],    bar: 'hello world',    baz: false  }});grunt.task.registerMultiTask('log', 'Log stuff.', function() {  grunt.log.writeln(this.target + ': ' + this.data);});

参见 创建任务 文档以获取更多复合任务的案例。

此方法还可以通过 grunt.registerMultiTask 调用。

grunt.task.requires

Fail the task if some other task failed or never ran.

grunt.task.requires(taskName);

grunt.task.exists

Added in 0.4.5

Check with the name, if a task exists in the registered tasks. Return a boolean.

grunt.task.exists(name)

grunt.task.renameTask

重命名任务。如果你希望覆盖某个任务的默认行为,并且希望保留原来的名字,这个函数将会很有用。

注意,如果一个任务已经被重命名了, this.name 和 this.nameArgs 属性都会发生相应的变化。

grunt.task.renameTask(oldname, newname)

此方法还可以通过 grunt.renameTask 调用。

加载外部定义的任务

对于多数项目来说,Gruntfile 文件中可能会定义很多任务。对于大型项目或者需要在多个项目中共享任务的情况,可以从一个或多个外部目录加载任务,或者从npm安装的 Grunt 插件加载任务。

grunt.task.loadTasks

从指定的目录(注意:相对于 Gruntfile 所在目录)加载任务相关的文件。此方法可以从本地Grunt插件加载任务相关的文件,只需指定包含"tasks"子目录的插件目录即可。

grunt.task.loadTasks(tasksPath)

此方法还可以通过 grunt.loadTasks 调用。

grunt.task.loadNpmTasks

从指定的 Grunt 插件中加载任务。此插件必须通过npm安装到本地,并且是参照 Gruntfile 文件的相对路径。Grunt插件还可以通过 grunt-init grunt插件模版创建: grunt init:gruntplugin

grunt.task.loadNpmTasks(pluginName)

此方法还可以通过 grunt.loadNpmTasks 调用。

队列任务

Grunt自动将命令行中指定的任务加入队列并执行,但是,一些独特的任务可以向队列中加入额外需要执行的任务。

grunt.task.run

将一个或多个任务放入队列中。 taskList 中的每个任务都会按照其在队列中的顺序,在当前任务执行完毕后立即执行。任务列表可以是一个任务数组或单个任务。

grunt.task.run(taskList)

grunt.task.clearQueue

完全清空任务队列。除非将额外的任务加入队列,否则将不会执行任何任务。

grunt.task.clearQueue()

grunt.task.normalizeMultiTaskFiles

将目标(target)的配置对象标准化为一个src-dest文件映射数组。此方法在内部由复合任务系统的this.files / grunt.task.current.files属性调用。

grunt.task.normalizeMultiTaskFiles(data [, targetname])

grunt.template

可以手工调用模板函数处理模版字符串。另外,config.get 方法(被很多任务所使用)会自动解析 <% %>类型的模版字符串,此类型的模版字符串是在 Gruntfile 中指的配置数据中定义的。

grunt.template.process

处理一个 Lo-Dash 模版 字符串。template 参数将被递归处理,知道没有任何模版位置。

默认的数据对象是整个配置对象,但是,如果设置了options.data,则使用该对象。默认的模板分隔符是<% %>,但是,如果options.delimiters被设置为自定义的形式(通过grunt.template.addDelimiters 进行设置),那么后续就会使用此模板分隔符。

grunt.template.process(template [, options])

在模板内部暴露了grunt对象,因此你可以这样做<%= grunt.template.tody('yyyy') %>注意, 如果数据对象已经有了grunt属性,那么在模板内部将无法访问grunt API。

在下面这个案例中,baz 属性被递归处理,直到再也没有多余的 <% %> 模版需要处理。

var obj = {  foo: 'c',  bar: 'b<%= foo %>d',  baz: 'a<%= bar %>e'};grunt.template.process('<%= baz %>', {data: obj}) // 'abcde'

grunt.template.setDelimiters

设置Lo-Dash模板的分隔符为预定义的形式,以防需要手动调用grunt.util._.templateconfig分隔符默认是<% %>

你可能永远不会使用这个方法,因为你所使用的 grunt.template.process 在内部使用的就是这个方法。

grunt.template.setDelimiters(name)

grunt.template.addDelimiters

Lo-Dash模板添加一个命名分隔符。你或许不需要使用这个方法,因为内置的分割符应该足以满足需求了,但是你仍可以随时添加{% %} 或者[% %]风格的分隔符。

name 参数应当是唯一的,因为这也是我们通过 grunt.template.setDelimiters 获取分隔符的方式,并且后续作为 grunt.template.process 的一个选项来使用。

grunt.template.addDelimiters(name, opener, closer)

在此实例中,如果我们希望使用 {% %} 形式的分隔符,我们需要如下这样设置:

grunt.template.addDelimiters('myDelimiters', '{%', '%}')

助手函数

grunt.template.date

使用dateformat library格式化一个日期。

grunt.template.date(date, format)

在这个案例中,指定的日期被格式化为 month/day/year。

grunt.template.date(847602000000, 'yyyy-mm-dd') // '1996-11-10'

grunt.template.today

使用 dateformat library格式化当前日期。

grunt.template.today(format)

在这个案例中,当前日期被格式化为4位数字表示的年份。

grunt.template.today('yyyy') // '2014'

grunt.util

各色工具函数/库,包括 Lo-Dash、Async 和 Hooker。

grunt.util.kindOf

返回给定值的"类型(kind)"。就像typeof,但是其返回的是内部的[Class](class/)值。可能返回的结果是"number""string""boolean""function""regexp""array""date""error""null""undefined"和可以表示一切类型的 "object"

grunt.util.kindOf(value)

grunt.util.error

返回一个新的Error实例(也可以抛出)与相应的消息。如果指定的是Error对象而不是message,则返回对象。

另外,如果为 origError 参数指定的是Error对象,并且使用 --stack 选项运行Grunt,则输出原始的Error堆栈。

grunt.util.error(message [, origError])

grunt.util.linefeed

将换行符转换为当前系统所采用的形式(Window上是 ,其他系统为 )。

grunt.util.normalizelf

对于一个给定的字符串,将其所有换行符转换为当前系统所采用的形式,然后返回一个新的字符串。(Window上是 ,其他系统为

grunt.util.normalizelf(string)

grunt.util.recurse

递归嵌套的对象和数组,为每个非对象值执行callbackFunction。如果continueFunction返回false, 给定的对象或值将会被跳过。

grunt.util.recurse(object, callbackFunction, continueFunction)

grunt.util.repeat

返回被重复n次的字符串str

grunt.util.repeat(n, str)

grunt.util.pluralize

给定一个"a/b"形式的str,如果n1,返回"a",否则返回"b"。如果不能使用'/',也可以指定一个自定义的分隔符。

grunt.util.pluralize(n, str, separator)

grunt.util.spawn

生成一个子进程,并跟踪其stdout、stderr和退出码。此方法返回子进程的引用。当子进程退出时,doneFunction 函数被调用。

grunt.util.spawn(options, doneFunction)

options 对象可以指定以下属性:

var options = {  // The command to execute. It should be in the system path.  cmd: commandToExecute,  // If specified, the same grunt bin that is currently running will be  // spawned as the child command, instead of the "cmd" option. Defaults  // to false.  grunt: boolean,  // An array of arguments to pass to the command.  args: arrayOfArguments,  // Additional options for the Node.js child_process spawn method.  opts: nodeSpawnOptions,  // If this value is set and an error occurs, it will be used as the value  // and null will be passed as the error value.  fallback: fallbackValue};

doneFunction 函数可以接收以下参数:

function doneFunction(error, result, code) {  // If the exit code was non-zero and a fallback wasn't specified, an Error  // object, otherwise null.  error  // The result object is an object with the properties .stdout, .stderr, and  // .code (exit code).  result  // When result is coerced to a string, the value is stdout if the exit code  // was zero, the fallback if the exit code was non-zero and a fallback was  // specified, or stderr if the exit code was non-zero and a fallback was  // not specified.  String(result)  // The numeric exit code.  code}

grunt.util.toArray

对于传入的数组或类数组对象,返回一个数组。对于将arguments对象转换为数组是非常有用的。

grunt.util.toArray(arrayLikeObject)

grunt.util.callbackify

标准化"返回值"和"传递结果给回调"的函数,总是传递一个结果给指定的回调函数。如果原始函数返回一个值,该值将即刻传递给回调函数,,并指定为最后一个参数,在所有的预定义参数之后。如果原始函数传递一个值给回调函数,,它也会继续照样如此。

grunt.util.callbackify(syncOrAsyncFunction)

下面这个例子也许能够更好的说明:

function add1(a, b) {  return a + b;}function add2(a, b, callback) {  callback(a + b);}var fn1 = grunt.util.callbackify(add1);var fn2 = grunt.util.callbackify(add2);fn1(1, 2, function(result) {  console.log('1 plus 2 equals ' + result);});fn2(1, 2, function(result) {  console.log('1 plus 2 equals ' + result);});

内部工具库

grunt.util.namespace

此内部工具库用于解析对象中深度嵌套的属性。

grunt.util.task

用于task执行的内部工具库。

外部工具库

不建议使用

下面列出的所有外部工具库已经不再建议使用了。

请使用 npm 管理项目中对第三方工具库的依赖。

例如,如果你需要使用 Lo-Dash,首先通过 npm install lodash 安装,然后在 Gruntfile 文件中使用即可: var _ = require('lodash');

grunt.util._

不建议使用

Lo-Dash - 很多有用的数组、函数和对象工具方法。 Underscore.string - 很多实用的字符串工具函数。

grunt.util._.str is available for methods that conflict with existing Lo-Dash methods.

grunt.util.async

不建议使用

Async - 对node和浏览器都适用的异步工具。

grunt.util.hooker

不建议使用

JavaScript Hooker - 用于调试和做些其他事情的钩子(hook)函数。

安装Grunt

这份文档详细解释了如何安装指定版本的 Grunt 和 Grunt 插件。如果你还没有阅读 快速入门 指南,请先将其看一遍。

概述

Grunt 和 Grunt 插件应当在项目的package.json文件中的devDependencies小节中定义。这样就可以通过一个命令将当前项目依赖的模块安装完毕:npm install。当前 Grunt 的稳定和开发版本都会在项目的wiki页面中列出。

安装指定版本的Grunt

如果你需要某个特定版本的 Grunt 或 Grunt 插件,执行npm install grunt@VERSION --save-dev 命令,其中VERSION代表你所需要的版本。这样就安装完成了,然后将其添加到package.json文件中的devDependencies小节中。

注意,当你在npm install命令后面添加了--save-dev 标记之后,package.json文件中出现的将是波浪线标记的版本范围 。一般情况下这样做很不错,当指定版本发布补丁更新后,新版本将被自动升级,并且按照semver定义的语义版本格式。

安装已经公布的开发版

随着新功能被开发出来,Grunt 会被定期的发布到npm上。如果不指定版本号,这种构建的版本是 根本不会被安装的,通常它们都会被指定构建码或 alpha/beta/release。

就像安装指定版本的 Grunt 一样,执行npm install grunt@VERSION --save-dev命令,其中VERSION 是你指定的版本,npm将在项目目录中安装此版本的grunt,并将其添加到package.json文件中的devDependencies小节。

注意,不管你指定的是什么版本,都将按照[波浪线标记的版本范围]将其添加到package.json文件中。这个危害很大,当指定的开发版出现新版本,尤其是不兼容的patch版本时,也会被npm安装,这就有可能扰乱你的项目,使其无法编译。

一旦出现这种情况,最重要的是要手工编辑 package.json文件,将 ~ (tilde)从版本号中去除掉。这样就能锁定到你所指定的某个具体的开发版本了。

这个技巧同样可以用于安装已经发布的 Grunt 插件的开发版本。

从github上直接安装

如果你需要安装最最最新的版本,而且这个 Grunt 或 Grunt 插件的版本并没有公布,按照下面的步骤来指定git URL 作为依赖 并且确保指定了具体的commit SHA (not a branch name) as the commit-ish。这将确保你的项目永远使用这个精确版本的grunt。

这个指定的git URL可以是官方的 Grunt 仓库,也可以是一个fork版本。

常见问题

如何安装grunt?

对于常规的安装说明,请阅读快速入门指南。如果在阅读完之后你需要更多的详细信息,你可以阅读更详细的的安装 Grunt指南。

什么时候我将可以使用开发中的'某某'特性?

安装 Grunt指南中介绍了如何安装已发布的和未发布的开发版本的Grunt。

Grunt可以在Windows上工作吗?

Grunt可以很好的在windows上工作,因为Node.jsnpm都能够很好的在windows上工作。通常情况下,问题在于Cygwin,因为它捆绑着一个较老版本的Node.js。

避免这个问题最好的办法是使用msysGit installer安装二进制的git和使用Node.js installer去安装二进制的nodenpm,然后使用内置的Windows command prompt 或 PowerShell 去替代Cygwin。

为什么我的异步任务不能执行完毕?

这是因为你忘记调用 this.async 方法来告知Grunt你的task是异步执行的。为了简化模型,Grunt采用同步模式的编码风格,你可以通过在任务中调用 this.async() 切换到异步模式。

注意,如果task执行失败,可以传递 false 给 done() 函数告知Grunt。

案例:

grunt.registerTask('asyncme', 'My asynchronous task.', function() {  var done = this.async();  doSomethingAsync(done);});

如何启用shell中的tab键自动补全功能?

为了给grunt增加tab键自动补功能,可以在你的~/.bashrc文件中添加下面一行代码:

eval "$(grunt --completion=bash)"

当然,假设你已经使用npm install -g grunt在全局安装好了Grunt。因为Grunt目前仅仅支持bash命令。

我如让多个任务共享参数?

虽然每个任务可以使用它自己的参数,但是,这里有几个方法允许你在多个task中共享参数。

"动态的" 任务别名

这是多个任务共享参数的首选方法

鉴于任务别名是很简单的,一个普通的task可以使用grunt.task.run让一个函数作为“动态的”任务别名。在下面这个案例中,在命令行中执行grunt build:001,最终效果是执行foo:001bar:001 和 baz:001这三个task。

grunt.registerTask('build', 'Run all my build tasks.', function(n) {  if (n == null) {    grunt.warn('Build num must be specified, like build:001.');  }  grunt.task.run('foo:' + n, 'bar:' + n, 'baz:' + n);});

-- 选项

多个任务共享参数的方式是使用grunt.option。在这里有一个例子,在命令行中执行grunt deploy --target=staging会让grunt.option('target')返回"staging"

grunt.registerTask('upload', 'Upload code to specified target.', function(n) {  var target = grunt.option('target');  // do something useful with target here});grunt.registerTask('deploy', ['validate', 'upload']);

注意,布尔类型的参数可以使用一个没有值的键。例如,在命令行中执行grunt deploy --staging会让grunt.option('staging') 返回true

全局和配置

在其他情况下,你可能希望暴露一个设置配置或者全局的值方法。 在这种情况下,可以在注册任务时设置其参数作为一个全局对象的或者项目配置的值。

在下面的例子中,在命令行运行grunt set_global:name:peter set_config:target:staging deploy会导致global.name的值为"peter"以及grunt.config('target')将会返回"staging"。由此推断,deploy任务就可以使用这些值。

grunt.registerTask('set_global', 'Set a global variable.', function(name, val) {  global[name] = val;});grunt.registerTask('set_config', 'Set a config property.', function(name, val) {  grunt.config.set(name, val);});

当出现错误时如何获取调用栈的追踪信息?

使用 --stack 参数就可以看到调用栈的追踪信息了。例如:grunt task --stack 。

为什么出现 "Maximum call stack size exceeded(超出最大调用栈大小)" 的错误?

你可能是为某个任务创建的别名和其他任务重名了。 例如:grunt.registerTask('uglify', ['uglify:my_target']); 应该是grunt.registerTask('myUglify', ['uglify:my_target']);

如何卸载或移除不需要的插件?

至少有两种方法。一种方法时利用 npm uninstall [GRUNT_PLUGIN] --save-dev 指令,这将从package.json 文件和 node_modules 目录下同时移除指定的插件。另一种方法时手工从 package.json文件中删除依赖项,然后执行 npm prune 指令。

出现错误 "Fail to install with npm error: No compatible version found"

请确保安装了最新稳定版本的 NPM 和 Node.JS


grunt 0.3 的相关问题

在Windows的 Grunt 0.3中,为什么当我尝试运行grunt时我的JS编辑器会打开?

如果你在Gruntfile所在的目录中时,当你输入grunt时Windows会尝试去执行那个文件。因此你需要输入grunt.cmd

另一个选择是使用DOSKEY命令去创建一个Grunt宏,请参考这篇文章。这样就可以使用grunt替代grunt.cmd了。

可以使用所示如下的DOSKEY命令:

DOSKEY grunt=grunt.cmd $*

项目脚手架

grunt-init

grunt-init是一个用于自动创建项目脚手架的工具。它会基于当前工作环境和你给出的一些配置选项构建一个完整的目录结构。至于其所生成的具体文件和内容,依赖于你所选择的模版和构建过程中你对具体信息所给出的配置选项。

注意:这个独立的程序曾经是作为Grunt内置的"init"任务而存在的。在从0.3升级到0.4指南中可以查看更多关于它演变的信息。

安装

为了使用grunt-init,需要将其安装到全局环境中。

npm install -g grunt-init

这样就会把grunt-init命令安装了到你的系统路径,从而允许你在任何目录中都可以运行它。

注意:你可能需要使用sudo权限或者作为超级管理员运行shell命令来执行这个操作。

用法

  • 使用grunt-init --help来获取程序帮助以及列出可用模板清单
  • 使用grunt-init TEMPLATE并基于可用模板创建一个项目
  • 使用grunt-init /path/to/TEMPLATE基于任意其他目录中可用的模板创建一个项目

注意,大多数的模板都应该在当前目录(执行命令的目录)中生成它们的文件(自动生成的项目相关的文件),因此,如果你不想覆盖现有的文件,注意一定要切换到一个新目录中来保证文件生成到其他目录。

安装模板

一旦模板被安装到你的~/.grunt-init/目录中(在Windows平台是%USERPROFILE%.grunt-init目录),那么就可以通过grunt-init命令来使用它们了。建议你使用git将模板克隆到项目目录中。例如, grunt-init-jquery模板可以像下面这样安装:

git clone https://github.com/gruntjs/grunt-init-jquery.git ~/.grunt-init/jquery

注意:如果你希望在本地像"foobarbaz"这样使用模板,你应该指定~/.grunt-init/foobarbaz之后再克隆。grunt-init会使用实际在于~/.grunt-init/目录中的实际的目录名。

下面是一些有Grunt官方维护的grunt-init模板:

定制模版

你可以创建和使用自定义模板。但是你的模板必须遵循与上述模板相同的文件结构。

下面是一个名为my-template的模板示例,它必须遵循下面这样的常规文件结构:

  • my-template/template.js - 主模板文件。
  • my-template/rename.json - 模板特定的重命名规则,作为模板进行处理。
  • my-template/root/ - f要复制到目标位置的文件。

假设这些文件存储在/path/to/my-template目录中,那么命令grunt-init /path/to/my-template就会处理这些模板。这个目录中可能存在多个命名唯一的模板(多个不重名的模板)。

此外,如果你把这个自定义模板放在你的~/.grunt-init/目录中(在Windows上是%USERPROFILE%.grunt-init目录),那么只需要使用grunt-init my-template命令就可以使用这个模版了。

复制文件

当执行初始化模板时, 只要模板使用init.filesToCopyinit.copyAndProcess方法,任何位于root/子目录中的文件都将被复制到当前目录。

注意所有被复制的文件都会被做为模板进行处理,并且所有{% %}模板都会依据props数据对象集合中的数据进行替换,除非设置了noProcess选项。可以看看jquery template中的案例。

重命名或者排除模板文件

rename.json用于描述sourcepathdestpath的重命名映射关系。sourcepath必须是相对于root/目录要被复制的文件路径,但是destpath值可以包含{% %}模板,用于描述目标路径是什么。

如果destpath被指定为false,那么文件就不会被复制。此外,srcpath还支持通配符匹配模式。

为询问信息指定默认选择

每个初始化提示都会有一个硬编码的默认值或者它会根据当前环境来尝试确定该缺省值。如果你想覆盖某个特定提示信息的默认值,你可以在OS X或者Linux的~/.grunt-init/defaults.json或者Windows的%USERPROFILE%.grunt-initdefaults.json文件中选择性的进行处理。

例如,由于我希望使用一个与众不同的名字来替代默认的名字,并且我还希望排除我的邮箱地址,同时我还希望自动指定一个作者的url,那么我的defaults.json看起来就可能像下面这样。

{  "author_name": ""Cowboy" Ben Alman",  "author_email": "none",  "author_url": "http://benalman.com/"}

注意:即使所有的内置提示信息都有文档,你还可以在源代码中找到他们的名字和默认值。

定义一个初始化模

exports.description

当用户运行grunt init或者grunt-init来显示所有可用的初始化模板时,这个简短的模板描述也会和模板名一起显示。

exports.description = descriptionString;

exports.notes

如果指定了这个选项,这个可选的扩展描述将会在任何提示信息显示之前显示出来。这是一个给用户提供一些解释命名空间相关帮助信息的很好的地方。这些提示可能是必选的也可能是可选的,等等。

exports.notes = notesString;

exports.warnOn

如果这个(推荐指定)可选的通配模式或者通配模式数组有匹配项出现,Grunt将终止并生成一个警告信息,用户可以使用--force来覆盖这个默认行为。这对于初始化模板可能覆盖现有文件的情况来说是非常有用的。

exports.warnOn = wildcardPattern;

然而最常见的值是'*',它能够匹配任意文件或者目录。使用minimatch通配符模式具有很大的灵活性。例如:

exports.warnOn = 'Gruntfile.js';        // Warn on a Gruntfile.js file.exports.warnOn = '*.js';            // Warn on any .js file.exports.warnOn = '*';               // Warn on any non-dotfile or non-dotdir.exports.warnOn = '.*';              // Warn on any dotfile or dotdir.exports.warnOn = '{.*,*}';          // Warn on any file or dir (dot or non-dot).exports.warnOn = '!*/**';           // Warn on any file (ignoring dirs).exports.warnOn = '*.{png,gif,jpg}'; // Warn on any image file.// This is another way of writing the last example.exports.warnOn = ['*.png', '*.gif', '*.jpg'];

exports.template

虽然exports属性定义在该函数的外面,然而所有实际的初始化代码指定在它内部。这个函数接受三个参数,grunt参数是一个grunt的引用,它包含所有的grunt方法和库init参数是一个包含特定于这个初始化模板而存在的方法和属性的对象。done参数是在初始化模板执行完成时必须调用的函数。

exports.template = function(grunt, init, done) {  // See the "Inside an init template" section.};

初始化模板的内部

init.addLicenseFiles

可以给files对象添加适当命名的许可协议证书文件。

var files = {};var licenses = ['MIT'];init.addLicenseFiles(files, licenses);// files === {'LICENSE-MIT': 'licenses/LICENSE-MIT'}

init.availableLicenses

返回一个可用许可协议证书的数组:

var licenses = init.availableLicenses();// licenses === [ 'Apache-2.0', 'GPL-2.0', 'MIT', 'MPL-2.0' ]

init.copy

它提供一份绝对或者相对源文件路径,以及一个可选的相对的目标文件路径,复制一个文件时,可以通过传递的回调函数来选择性的处理它。

init.copy(srcpath[, destpath], options)

init.copyAndProcess

遍历所传递对象中的所有文件,将源文件复制到目标路径,并处理相关内容。

init.copyAndProcess(files, props[, options])

init.defaults

用户在defaults.json中指定的默认初始值。

init.defaults

init.destpath

目标文件的绝对路径。

init.destpath()

init.expand

grunt.file.expand相同。

返回一个独一无二的与给定通配符模式所匹配的所有文件或目录路径数组。这个方法接收一个逗号分割的通配符模式或者数组形式的通配符模式参数。如果路径匹配模式以!开头,与模式所匹配的结果就会从返回的数组中排除。模式是按顺序处理的,所以包含和排除在数组中出现的顺序是非常重要的。

init.expand([options, ] patterns)

init.filesToCopy

返回一个包含待复制文件的对象,每个文件都包含了源文件的绝对路径和目标文件的相对路径,并按照rename.json(如果存在)中的规则进行重命名(或者忽略)。

var files = init.filesToCopy(props);/* files === { '.gitignore': 'template/root/.gitignore',  '.jshintrc': 'template/root/.jshintrc',  'Gruntfile.js': 'template/root/Gruntfile.js',  'README.md': 'template/root/README.md',  'test/test_test.js': 'template/root/test/name_test.js' } */

init.getFile

获取单一的任务文件路径。

init.getFile(filepath[, ...])

init.getTemplates

返回一个包含所有可用模板的对象。

init.getTemplates()

init.initSearchDirs

在初始化目录中搜索初始化模板。template是指模板的位置。还包括~/.grunt-init和grunt-init中的核心初始化任务。

init.initSearchDirs([filename])

init.process

启动程序并提示开始输入。

init.process(options, prompts, done)
init.process({}, [  // Prompt for these values  init.prompt('name'),  init.prompt('description'),  init.prompt('version')], function(err, props) {  // All finished, do something with the properties});

init.prompt

给用户一个提示,并让用户输入自己选择的值。

init.prompt(name[, default])

init.prompts

此对象包含了所有提示信息。

var prompts = init.prompts;

init.readDefaults

读取任务文件中(如果存在)读取JSON格式的默认值,并将它们合并到一个数据对象中。

init.readDefaults(filepath[, ...])

init.renames

模板的重命名规则。

var renames = init.renames;// renames === { 'test/name_test.js': 'test/{%= name %}_test.js' }

init.searchDirs

搜索模板的目录数组。

var dirs = init.searchDirs;/* dirs === [ '/Users/shama/.grunt-init',  '/usr/local/lib/node_modules/grunt-init/templates' ] */

init.srcpath

根据文件名搜索初始化模板路径并返回一个绝对路径。

init.srcpath(filepath[, ...])

init.userDir

返回用户模板目录的绝对路径。

var dir = init.userDir();// dir === '/Users/shama/.grunt-init'

init.writePackageJSON

在目标目录中保存一个package.json文件。回调函数可以用于后置处理属性的添加/移除/其他操作。

init.writePackageJSON(filename, props[, callback])

内置提示

author_email

用于package.json中的作者邮箱地址。默认情况下会尝试从用户的git配置中找到一个默认值。

author_name

用于package.json中的作者全名和版权信息。也会尝试从用户的git配置中找到一个默认值。

author_url

package.json中的用于公开作者个人网站的URL。

bin

项目根目录中cli脚本的相对路径。

bugs

用于项目问题跟踪的公开URL。如果项目有一个Github仓库,将自动指向项目Github的问题跟踪模块(issue)。

description

项目的描述。通常在package.json或者README文件中。

grunt_version

项目所需的有效Grunt版本范围定义。

homepage

指向项目首页的公开URL。如果此项目使用的是github仓库,那么,默认是Github仓库的url。

jquery_version

如果是jQuery项目,它表示项目所需的jQuery版本。必须是一个有效的版本范围定义。

licenses

项目许可协议证书。多个许可协议证书使用空格分割,内置的许可协议有:MITMPL-2.0GPL-2.0Apache-2.0。默认是MIT协议。可以使用init.addLicenseFiles方法添加自定义许可协议证书。

main

项目的主入口。默认是lib目录已项目名称命名的文件。

name

项目名称。在项目模版中将会大量使用,默认指向当前工作目录。

node_version

项目所需的Node.js版本。必须是一个有效的版本范围定义。

npm_test

项目中运行测试的命令,默认情况下是grunt

repository

项目的git仓库。默认是一个猜测的github url。

title

适合大家识别的项目名称。默认是原始项目名称,并且经过过滤,适合大家识别。

version

项目的版本号。默认是第一个有效的语义版本号:0.1.0

深入任务内幕

当一个任务执行时,Grunt通过 this 对象向此任务函数暴露了很多任务特定的属性和方法。 同样这个对象也将暴露为grunt.task.current的形式在 templates中使用,例如,this.name属性也可以作为grunt.task.current.name来使用。

所有任务内部都可以使用的方法/属性

this.async

如果一个任务是异步的,必须调用此方法以通知Grunt。此方法返回一个 "done" 函数,应当在任务执行完毕后调用。false 或 Error 对象都可以传递给done函数,以通知Grunt此任务执行失败。

如果 this.async 方法没有被调用,此任务将会同步执行。

// Tell Grunt this task is asynchronous.var done = this.async();// Your async code.setTimeout(function() {  // Let's simulate an error, sometimes.  var success = Math.random() > 0.5;  // All done!  done(success);}, 1000);

this.requires

如果一个任务依赖于另外一个(或一些)任务的成功执行,在其依赖的任务没有运行或者运行失败的情况下,这个方法可以被用来强制Grunt退出。作为这个方法的参数,其依赖的任务列表可以是一个包含多个任务名称的数组,也可以是单个的任务名称。

注意,实际上这个方法并不会运行指定任务列表中的任务,它只是在任务列表中的任务没有成功运行的时候通知系统当前的任务失败了。

this.requires(tasksList)

this.requiresConfig

这个方法可以指定一个或者多个字符串或者数组的配置属性为必需的。如果一个或多个必需的配置属性缺失,就通知系统当前任务失败。

this.requiresConfig(prop [, prop [, ...]])

查看grunt.config文档了解更多关于配置属性相关的信息。

这个方式是grunt.config.requires方法的一个别名。

this.name

当前任务的名称,和定义在grunt.registerTask中的任务名一致。例如,如果以grunt sample或者grunt sample:foo的方式运行一个名为"sample"的任务,那么在这个任务函数内部,this.name的值就是"sample"

注意,如果通过grunt.task.renameTask 重命名了一个task,此属性也会跟着变为新名字。

this.nameArgs

当前任务的名称,包括在命令行中指定的任意使用逗号分割的参数或者标记。例如,如果以grunt sample:foo的方式运行一个名为"sample"的任务,那么在这个任务函数内部,this.nameArgs的值就是"sample:foo"

注意,如果一个任务使用grunt.task.renameTask方法重命名过,那么这个属性也会指向对应的新名称。

this.args

传递给当前任务的参数数组。例如,以grunt sample:foo:bar的方式运行一个名为"sample"的任务,那么在这个任务函数内部,this.args的值就是["foo", "bar"]

注意,在多任务形式中,当前目标(名)会从this.args数组中省略。

this.flags

根据传递给当前任务的参数生成的一个对象。例如,以grunt sample:foo:bar的形式运行一个名为"sample"的任务,那么在这个任务函数内部,this.flags的值是{foo: true, bar: true}

注意,在多任务形式中,任务目标名不会被设置为一个标记。

this.errorCount

当前任务执行期间grunt.log.error方法被调用的次数。如果在任务运行期间有错误信息输出,它可以用来让任务执行失败。

this.options

返回一个options对象。defaultsObj是一个可选参数,它的属性会被任意的任务级options对象的属性覆盖;在多任务形式中,它的属性会进一步被目标级的options对象的属性覆盖。

this.options([defaultsObj])

下面给出了一个例子,展示了在任务中可以如何使用this.options方法:

var options = this.options({  enabled: false,});doSomething(options.enabled);

配置任务指南中,有一个例子展示了如何从用户任务的角度来指定options。

多任务形式内部可用的方法/属性

this.target

在一个多任务形式中,这个属性包含了当前正被遍历的目标的名称。例如,如果一个名为"sample"的多任务带有{sample: {foo: "bar"}}这样的配置数据,当以grunt sample:foo的形式运行这个任务时,那么在这个任务函数内部,this.target属性的值就为"foo"

this.files

在一个多任务形式中,使用Grunt支持的文件格式和选项通配符模式或者动态映射方式指定的文件,都会被自动标准化为一个唯一的格式:即文件数组格式

这意味着,任务不需要为了明确的处理自定义文件格式,通配符格式,源文件到目标文件映射或者过滤输出文件或者目录而包含大量模板。任务只需要根据配置任务指南中的说明指定文件,Grunt会自动处理所有任务细节。

this.files属性永远都是一个数组。你的任务应该利用数组中每个对象的srcdest属性遍历this.files数组。在你的任务关注每个目标文件的多个源文件的情况下,src`属性也永远是一个数组。

注意,有可能不存在的文件也被包含在 src 的值当中,因此,你应该在使用前检查源文件是否存在。

下面的例子展示了一个简单的"concat"任务是怎样使用this.files属性的:

this.files.forEach(function(file) {  var contents = file.src.filter(function(filepath) {    // Remove nonexistent files (it's up to you to filter or warn here).    if (!grunt.file.exists(filepath)) {      grunt.log.warn('Source file "' + filepath + '" not found.');      return false;    } else {      return true;    }  }).map(function(filepath) {    // Read and return the file's source.    return grunt.file.read(filepath);  }).join('
');  // Write joined contents to destination filepath.  grunt.file.write(file.dest, contents);  // Print a success message.  grunt.log.writeln('File "' + file.dest + '" created.');});

如果你还需要使用原始文件对象的属性,可以通过每个单独的文件对象的orig属性来获取并使用,但是目前都没发现有访问原始属性的用例。

this.filesSrc

在多任务形式中,在src中通过任意的文件格式指定的文件都会被归并到一个数组。如果你的任务是"只读"的并且无需关心目标文件路径,可以使用这个数组来替代this.files

下面这个例子展示了一个简单的"lint"的任务是怎样使用this.filesSrc属性的:

// Lint specified files.var files = this.filesSrc;var errorCount = 0;files.forEach(function(filepath) {  if (!lint(grunt.file.read(filepath))) {    errorCount++;  }});// Fail task if errors were logged.if (errorCount > 0) { return false; }// Otherwise, print a success message.grunt.log.ok('Files lint free: ' + files.length);

this.data

在多任务形式中,这是存储在给定目标的Grunt配置对象中的实际数据。例如,如果一个名为"sample"的多任务带有{sample: {foo: "bar"}}这样的配置数据,当以grunt sample:foo的形式运行这个任务时,那么在这个任务函数内部,this.data的值就为"bar"

推荐使用this.optionsthis.filesthis.filesSrc来替代this.data, 因为它们的值都是经过标准化的。

退出码

  • 0 - 无错误!
  • 1 - 致命错误
  • 2 - 未找到gruntfile
  • 3 - Task 错误
  • 4 - 模版处理错误
  • 5 - 无效的shell自动完成规则
  • 6 - 警告