2.2 Grunt是如何工作的
Grunt为开发者提供了一个工具包,用于创建命令行程序来执行项目构建过程中的重复性任务,如压缩JavaScript代码、编译Sass样式表等。不过,Grunt的能力并不限于创建简单的任务(通常这些任务不会被分享或者复用),以解决特定工程遇到的特定需求,其真正的力量源于其将任务打包为可复用的插件的能力。这些插件可以被发布、分享、使用以及由其他人进行改进。本书写作之时已经有超过4 400个这样的插件。
Grunt的运转依赖于四个核心组件,接下来逐一论述。
2.2.1 Gruntfile.js
在Grunt中处于核心地位的是Gruntfile——一个位于工程根目录下的名为Gruntfile.js(见清单)的Node模块。正是这个文件使得我们可以加载Grunt插件,创建自定义任务,并根据项目需求对它们进行配置。Grunt每次运行时的首要任务都是接受该模块发出的指令。
清单2-2 Gruntfile示例
// example-starter/Gruntfile.js
module.exports = function(grunt) {
/**
* 配置即将用到的任务和插件
*/
grunt.initConfig({
/* Grunt的file API为开发者提供了与文件系统进行交互所必需的抽象。稍后,我们将在
本章对此进行深入了解。*/
'pkg': grunt.file.readJSON('package.json'),
'uglify': {
'development': {
'files': {
'build/app.min.js': ['src/app.js', 'src/lib.js']
}
}
}
});
/**
* Grunt插件以Node包的形式存在,并由npm发布。这里,我们加载的是grunt-contrib-uglify插件。
* 该插件包含的任务可以对项目源代码进行合并与压缩,以备发布之用。
*/
grunt.loadNpmTasks('grunt-contrib-uglify');
/**
* 这里,我们创建了一个名为default的任务,其仅有的功能就是调用uglify任务。换句话说,该任务
* 实际上是uglify任务的别名。名为default的任务指明了在命令行中不带参数调用Grunt时应当执
* 行的动作。在本例中,我们的default任务仅仅调用了一个单独的任务。不过(依次)调用多个任务
* 其实同样简单,只要在传入的数组中添加多个条目即可。
*/
grunt.registerTask('default', ['uglify']);
/**
* 这里,我们创建了一个自定义任务,利用Grunt内置的用户反馈(user feedback)方法,向控制台
* 输出一条消息(后面还有一个换行符)。稍后,我们将在本章对此做深入了解。
*/
grunt.registerTask('hello-world', function() {
grunt.log.writeln('Hello, world.');
});
};
2.2.2 任务(Tasks)
作为Grunt的基本构建模块,任务实际上只是由Grunt的registerTask()方法注册的具名函数。清单所示的hello-world任务将向控制台输出一条消息。在命令行中调用该任务的结果,如清单所示。
清单2-3 运行清单中所示的hello-world任务
$ grunt hello-world
Running "hello-world" task
Hello, world.
Done, without errors.
如清单所示,多个Grunt任务也可以由单条命令调用执行。每个任务都将按照参数的传入顺序依次执行。
清单2-4 顺序运行多个任务
$ grunt hello-world uglify
Running "hello-world" task
Hello, world.
Running "uglify:development" (uglify) task
>> 1 file created.
Done, without errors.
我们刚看到的hello-world任务是简单独立型Grunt任务的代表。这样的任务可以用于实现一些简单的功能,以解决特定项目的需求。通常我们不会考虑其复用或者分享的问题。但是多数时候,你会发现我们实际用到的都不是这样的独立型任务,而是那些已经打包为Grunt插件并发布到npm的任务。以插件的形式发布更便于别人使用或者参与改进。
2.2.3 插件(Plugins)
Grunt插件是一系列能够用于不同项目的可配置任务(以npm包的形式发布)的集合。现存的Grunt插件数以千计,可谓洋洋大观。清单中的Grunt方法loadNpmTasks()用以加载名为grunt-contrib-uglify的Node模块。该模块可以将工程中的JavaScript代码合并为单个压缩(minified)文件,以适应发布需求。
2.2.4 配置
Grunt以强调“配置优先”(configuration over code)而著称:任务和插件的功能均可通过配置文件进行定制,以适应不同工程的需求。正是这种代码与配置分离的特性,使开发者能够创造出容易被复用的插件。本章稍后将介绍配置Grunt插件和任务的各种不同的方法。