示例 Gruntfile
在本页中,我们将引导您创建一个涵盖简单项目常见需求的 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']);
};
要求
每个项目都有自己的需求,但大多数项目都有一些共同点。在本指南中,我们将向您介绍一些 Grunt 插件来自动化基本需求。最终目标是教您如何配置这些 Grunt 插件,以便您可以在项目中使用它们。
为了举例说明,假设您正在创建一个 JavaScript 库。典型的文件夹结构包含以下文件夹:src
、dist
和 test
。src
文件夹(有时称为 app
)包含您编写的库的源代码。dist
文件夹(有时称为 build
)包含发行版,即源代码的缩小版。缩小文件是指删除了所有不必要的字符(例如空格、换行符、注释)的文件,而不会影响源代码的功能。缩小后的源代码对项目的使用者特别有用,因为它减少了需要传输的数据量。最后,test
文件夹包含用于测试项目的代码。在下一节中创建 Gruntfile
配置时,将使用此设置。
在开发库和发布新版本时,您需要定期执行一些任务。例如,您可能希望确保您编写的代码符合最佳实践,或者您编写的代码不会导致意外行为。为此,您可以使用名为 JSHint 的工具。Grunt 有一个官方插件,名为 grunt-contrib-jshint,我们将在本例中采用它。特别是,您可能希望确保在修改代码时,不会破坏任何规则或最佳实践。因此,一个好的策略是在每次更改时检查代码。为此,我们将介绍一个名为 grunt-contrib-watch 的 Grunt 插件。每当添加、更改或删除文件时,后者都会运行预定义的任务,例如 grunt-contrib-jshint
。
检查源代码是否遵循最佳实践不足以保证其稳定且不包含错误。要创建一个健壮的项目,您需要对其进行测试。您可以采用多个库,例如 QUnit 或 Jasmine。在本指南中,我们将介绍如何配置 QUnit,特别是 grunt-contrib-qunit,来测试您的代码。
在分发您的工作成果时,您希望提供一个尽可能小的版本。要创建缩小版本,您需要一个 Grunt 插件,例如 grunt-contrib-uglify。此外,除非您正在开发的项目非常小,否则您很可能已将代码拆分到多个文件中。虽然这对开发人员来说是一个好习惯,但您希望用户只包含一个文件。因此,在缩小代码之前,您应该连接源文件以创建一个文件。为了实现此目标,您需要一个 Grunt 插件,例如 grunt-contrib-concat。
总而言之,在本指南中,我们将使用以下五个 Grunt 插件
- grunt-contrib-uglify
- grunt-contrib-qunit
- grunt-contrib-concat
- grunt-contrib-jshint
- grunt-contrib-watch
如果您对最终结果感到好奇,可以在本页底部找到完整的 Gruntfile
。
设置 Gruntfile
第一部分是“包装器”函数,它封装了您的 Grunt 配置。
module.exports = function(grunt) {
};
在该函数中,我们可以初始化配置对象
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-contrib-concat
的配置位于 concat
键下的配置对象中,如下所示
concat: {
options: {
// define a string to put between each file in the concatenated output
separator: ';'
},
dist: {
// the files to concatenate
src: ['src/**/*.js'],
// the location of the resulting JS file
dest: 'dist/<%= pkg.name %>.js'
}
}
请注意,在上面的代码段中,我们如何引用 JSON 文件中的 name
属性。我们通过使用 pkg.name
来访问它,因为之前我们将 pkg
属性定义为加载 package.json
文件的结果,然后将其解析为 JavaScript 对象。Grunt 有一个简单的模板引擎来输出配置对象中属性的值。在这里,我们告诉 concat
任务连接 src/
中存在的所有以 .js
结尾的文件。
现在让我们配置 grunt-contrib-uglify
插件,它可以缩小 JavaScript 代码
uglify: {
options: {
// the banner is inserted at the top of the output
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
dist: {
files: {
'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
}
}
}
此代码段告诉 grunt-contrib-uglify
在 dist/
中创建一个文件,该文件包含缩小 JavaScript 文件的结果。在这里,我们使用 <%= concat.dist.dest %>
,因此 uglify 将缩小 concat 任务生成的文件。
到目前为止,我们已经配置了插件来创建库的发行版本。现在是时候使用 grunt-contrib-qunit
来自动化代码测试了。为此,我们需要指定测试运行程序文件的位置,这些文件是 QUnit 运行的 HTML 文件。生成的代码如下所示
qunit: {
files: ['test/**/*.html']
},
完成后,就可以设置配置以确保项目的代码符合最佳实践。JSHint 是一个可以检测问题或潜在问题的工具,例如高循环复杂度、使用相等运算符而不是严格相等运算符,以及定义未使用的变量和函数。
我们建议您使用 grunt-contrib-jshint
分析项目的所有 JavaScript 文件,包括 Gruntfile
和测试文件。grunt-contrib-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 网站上有记录。如果您对插件默认值感到满意,则无需在 Gruntfile 中重新定义它们。
最后一个要配置的插件是 grunt-contrib-watch
。我们将使用它在添加、删除或修改 JavaScript 文件后立即运行 jshint
和 qunit
任务。当它检测到指定的任何文件已更改时(此处,我们使用与告诉 JSHint 检查的文件相同的文件),它将按出现的顺序运行您指定的任务。这可以在命令行中使用 grunt watch
运行。
将前面的描述转换为 grunt-contrib-watch
的配置会生成以下代码段
watch: {
files: ['<%= jshint.files %>'],
tasks: ['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');
最后设置一些任务。这些任务中最重要的是默认任务
// this would be run by typing "grunt test" on the command line
grunt.registerTask('test', ['jshint', 'qunit']);
// the default task can be run just by typing "grunt" on the command line
grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);
当您调用 Grunt
而不指定要执行的任务(grunt
)时,将执行默认任务。
生成的 Gruntfile
如果您已正确按照本指南进行操作,则应该具有以下 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") %> */\n'
},
dist: {
files: {
'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
}
}
},
qunit: {
files: ['test/**/*.html']
},
jshint: {
files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
options: {
// options here to override JSHint defaults
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']);
};