Grunt - 基于任务的Javascript构建工具

前言

软件项目的构建是针对项目的源代码,对其进行编译、代码质量检查、测试、打包等一系列流水线似的任务,使其成为一个可运行的软件产品的过程。而构建工具则是能够响应构建活动中一系列任务的自动化工具,它必须要简单灵活快速易扩展,从而帮助开发人员更快更高效的集成与发布。

回顾我们当前的开发语言,在.net世界里有MsBuild、NuGet和Nscaffold;在Ruby世界里有Rake、Gem和bundle; Java世界里有Ant, Maven, Ivy, Gradle,那么Javascript呢? Npm? 让我们来看一下Grunt.

Why Grunt

Automation

作为一个Web项目,Javascript/Css是前端开发的核心技术。和其他语言一样,它的构建也包括了Javascript代码的编译、测试、打包等行为,具体包括:

  1. 代码合并压缩
  2. CSS合并压缩
  3. 静态代码检查
  4. 单元测试
  5. 部署

涉及到的前台多数的工具包,如uglify,closure,jslint,jasmine等,而如何整合不同语言工具包下的构建流程是长久以来前端项目的一个问题。Grunt 是这样一个Javascript语言的基于任务的命令行构建工具,它依赖于npm进行包及插件管理,能够自动化项目定义的一系列构建任务,从而减轻开发人员在构建方面的开发成本与运行成本。

目前,JQuery, Adobe, Twitter, AnguarlJS 都已经引入Grunt作为开发项目的构建工具。

Grunt初探

1. 安装

Grunt基于npm进行安装和插件管理,所以安装Grunt之前需要安装nodejs(npm),然后安装grunt-cli以使用Grunt。

install
1
npm install -g grunt-cli

2. Grunt配置文件

Grunt依赖于两个配置文件,Package.json 和Gruntfile.js。

1) Package.json是当前项目依赖的npm modules信息,当运行 npm install时,会自动查找package.json中的dependencies信息,并进行自动安装.
创建Package.json文件有多种方式,可以选用npm init方式。

package.json
1
2
3
4
5
6
7
8
{
"name": "my-project-name",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.1.1",
""
}

2) Gruntfile.js是Grunt工具的配置文件,定义了项目的基本信息、需要的构建任务(项目的代码路径,输出路径)、依赖的插件等内容,语法及配置非常简单易懂,具体可详见Grunt的在线文档-配置任务

可以用 grunt-init 来创建一个Gruntfile.js,也可以直接写一个,如下例。

下面例子中,uglify是一个压缩的构建任务,在配置选项里定义需要被压缩的文件和输出的文件。

gruntfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = function(grunt) {

// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: { // task name
options: {
banner: 'banner'
},
build: { // target
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
});

// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');

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

};

当有了Gruntfile.js后,可以在当前项目目录下执行Grunt命令,Grunt会自动执行default任务组。

3. Task

Task是Grunt运行的最基本单元。Task可以是一个npm module,也可以自定义。Task的执行是有顺序的,它的顺序依赖于注册时的先后。

define task
1
2
grunt.registerTask(taskName, [description, ] taskList)

每个Task在gruntFile.js的 grunt.initConfig 代码块中进行配置,包含Task的名字, Target,以及选项-通常是source,destination或者files,比如我们刚才看到的uglify就是一个典型任务。

Grunt会默认定义一个default任务,如果Grunt运行时不带任何参数,会默认执行default 任务以及它所依赖的任务列表。

Grunt支持单一任务和多任务,多任务可以有多个targets,比如对于项目的文件在编译时可以输出到不同的路径,那么就可以定义一个有两个target的多任务。

multi task
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
grunt.initConfig({
compile: {
test: {
src : [],
dest : {}
},
production: {
src: [],
dest: {}
}
}
});

grunt.registerMultiTask('compile', 'compile stuff.', function() {
grunt.log.writeln(this.target + ': ' + this.data);
});

4. Plugins

每一个插件都是一个npm module,由npm进行管理。Grunt的插件是Grunt的一大特点,实现比较简单,使得Grunt的扩展非常容易。

目前常用的有:

名字 插件 说明
clean grunt - contrib - clean 删除指定目录或文件
copy grunt-contrib-copy 复制文件到指定目录
concact grunt-contrib-concact 合并文件,包括javascript/css等
uglify grunt-contrib-uglify 对指定的javascript进行压缩
useminPrepare grunt-usemin 搜索主页面加载javascript或css文件的代码,获取路径配置相关任务
usemin grunt-usemin 修改主页面,将javascript/css文件块替换为压缩后的文件
cssmain grunt-contrib-cssmain 压缩css文件
requirejs grunt-contrib-requirejs 解析系统的requirejs及module
jasmine grunt-contrib-jasmine 运行测试
watch grunt-contrib-watch 检测文件修改自动执行某些既定的任务


如何创建插件以及已有插件列表可以在Grunt Source以及网站Grunt Plugins查到。

5. Apply Grunt and plugins

上述概念了解过后,我们就可以来看一下如何安装grunt和应用插件。

  • Grunt
install
1
npm instal grunt --save-dev
  • Plugins
install
1
npm install grunt-contrib-uglify --save-dev

这些基于grunt的插件信息会被更新到package.json文件中,可以参见Grunt Getting Started文档。

总结

结合项目试用了Grunt之后,觉得很喜欢。它的一大特点就是简单,简单清晰的配置文件Gruntfile.js令人爱不释手,以前需要写很多脚本的事情,现在用几个插件配一下很容易搞定;第二就是易扩展,灵活小巧的插件使得开发人员自定义功能或者扩展修改都非常的方便。这些都是在以前Javascript项目中很难短时间内做到的,极大的节省了开发成本,提高效率。

回到前言中的问题,在javascript的世界里我们也有了自己的构建工具Grunt。Grunt目前为止是0.4版本,作为一个刚起步的软件构建工具,它还缺少一些必要的功能,比如依赖管理;在构建项目开发框架与IDE集成方面也可以有更多的结合。Grunt团队也在致力于将其完善与优化,力图使之灵活简单易扩展,看看它的release note,我对它的将来还是很看好的,希望它能走的很远。同时,YeoBowerBrunch也都是值得关注与尝试应用的项目。

参考
Share Comments