在软件开发中使用自动化构建工具的好处是显而易见的。通过工具自动化运行大量单调乏味、重复性的任务,比如图像压缩、文件合并、代码压缩、单元测试等等,可以为开发者节约大量的时间,使我们能够专注于真正重要的、有意义的工作,比如设计业务逻辑,编写代码等等。
对很多前端开发人员而言,Grunt 无疑是这方面的首选。基本上,如果你会用 JavaScript ,那么在一个名为 Gruntfile.js (或者 Gruntfile)的文件中用 Javascript 语言定义自动化任务是非常简单的过程,同时大量的 第三方插件 例如 JSHint, Sass 以及 Uglify 也使得 Grunt 具有了良好的可扩展性。
大多数情况下,Grunt 一直是前端构建工具的首选。但是最近一个名为 Gulp.js 的新工具正在吸引越来越多的人的关注。相比 Grunt, 它具有可读性更强、更利于理解的配置文件,更简单地配置过程。
接下来我们就一起来看看如何安装 Gulp, 并通过一个简单的案例让你感受一下这个新的构建工具。
安装 Gulp.js
Gulp.js 是基于 Node 的构建工具,类似 Grunt, 要使用它,你的机器上需要装有 Node.js。有关如何安装 Node, 这里就不再赘述,可以参考官网的指导。如果你之前完全不了解 Node.js, 可以参考一下 Nettuts+ 上面的系列教程。 有了 Node.js, 安装 Gulp.js 就非常容易了,只需要通过 npm (Node 包管理工具) 来安装即可。在命令行模式下执行:
npm install -g gulp
|
这样就可以将 gulp 以全局方式安装到你的电脑上,以后可以随时通过命令行的 gulp 命令来调用。
在前端项目中配置 Gulp.js
要在你的项目中使用 Gulp, 有几个关键的步骤需要完成:
- 安装两个依赖包
- 安装你需要的任意插件
- 创建 gulpfile.js 文件,在其中定义你要运行的任务
这些步骤需要在你的项目根目录下完成。
首先,要安装依赖项:
npm install --save-dev gulp gulp-util
|
接下来,安装我们需要使用到的 Gulp 插件,这些插件同样也都是 Node 模块,我们同样使用 npm 命令来安装它们:
npm install --save-dev gulp-uglify gulp-concat
|
在上面的例子中,安装了两个插件 gulp-uglify 和 gulp-concat, 通过它们可以对 Javascript 文件进行合并和压缩。
注意这里使用了 --save-dev 参数来安装 Gulp 依赖和插件,加上这个参数以后,在安装这些包的同时,也会把它们添加到我们的包配置文件 package.json:
{
"devDependencies": {
"gulp": "^3.6.2",
"gulp-concat": "^2.2.0",
"gulp-uglify": "^0.2.1",
"gulp-util": "^2.2.14"
}
}
这样可以确保项目所需的依赖包可以便捷地通过 npm 来进行安装。 如果你的项目没有 package.json 文件,可以在命令行通过 npm init
来创建, 也可以通过文本编辑器创建。这是 npm 相关的知识,这里就不细说了。
在前面的例子中,只安装了两个插件,Gulp 提供了超过 200 个插件, 涵盖了前端开发流程中的很多工作,包括但不限于:
- LiveReload (gulp-livereload)
- JSHint (gulp-jshint)
- Sass (gulp-sass)
- CoffeeScript file compilation (gulp-coffee)
还有很多,可以到 Gult plugins 进行搜索。
Gulpfile.js 文件
与 Grunt 一样, Gulp 也有一个同名配置文件,叫做 gulpfile.js, 在这个文件里定义需要用到什么插件,执行什么任务,如何执行等等。 这个文件应该存放在你的项目根目录下。
到目前为止,一切看起来都和 Grunt 没什么区别,那么为什么要介绍 Gulp 呢?接下来就是它的优势所在了。 gulpfile.js 的语法非常简单直接,具有非常好的可读性,便于理解。看一下例子:
var gulp=require('gulp'),
gutil=require('gulp-util'),
uglify=require('gulp-uglify'),
concat=require('gulp-concat');
这就是一条非常简单的 Javascript 变量定义语句,它告诉 Gulp 我们需要哪些插件来完成下面的任务定义。
接下来,我们要定义需要 Gulp 去运行的任务。在这个例子中,需要 Gulp 去完成两件事:
- 压缩 Javascript 文件
- 合并 Javascript 文件
在 Gulp 中,定义任务非常直接,就是调用 Javascript 的方法。我们通过 Gulp 提供的 task()
方法来定义任务:
gulp.task('js', function() {
gulp.src('./js/*.js')
.pipe(uglify())
.pipe(concat('all.js'))
.pipe(gulp.dest('./js'));
});
看一下上面的代码,gulp.task(name, callback)
方法需要两个参数,第一个是任务名称,第二个是回调函数。这个一看就明白了,没什么要解释的。看一下回调函数里面的代码:
gulp.src('./js/*.js')
src()
方法用来指定要处理的 js 文件的位置,它会获取匹配到的所有 js 文件的路径,并将它们转换为可以传递给插件进行处理的“流”。这是 Node.js 的 Streams API 的组成部分,也是 Gulp 能够实现如此简洁的 API 语法的原因。
.pipe(uglify())
pipe()
方法获取刚才通过 src()
方法获得并传递过来的“流”,并将其传递给指定的插件。本例中是 uglify 插件。
.pipe(concat('all.js'))
与 uglify 一样,concat 插件通过 pipe()
方法接收经过上一个方法处理之后返回的“流”,并把他们该“流”中的所有 Javascript 文件合并为一个名为 "all.js" 的文件。
.pipe(gulp.dest('./js'));
最后,通过 Gulp 的 dest()
方法, "all.js" 被写入到我们指定的目录。整个过程非常直观,易于理解。可以想象一下 jQuery 的链式调用,也可以想象一下 *nix 系统下的 grep, awk 这些命令。
我们要做的最后一件事,是指定 Gulp 的默认任务,让它执行我们刚才定义的 "js" 任务。
gulp.task('default', ['js']);
完整的 gulpfile.js:
// 定义依赖项和插件
var gulp=require('gulp'),
gutil=require('gulp-util'),
uglify=require('gulp-uglify'),
concat=require('gulp-concat'); // 定义名为 "js" 的任务
gulp.task('js', function(){
gulp.src('./js/*.js')
.pipe(uglify())
.pipe(concat('all.js'))
.pipe(gulp.dest('./js'));
}); // 定义默认任务
gulp.task('default', ['js']);
回到命令行(项目根目录),输入 gulp
, 回车。 Gulp 找到 gulpfile.js 文件,加载依赖的插件,启动默认任务,然后执行我们的 "js" 任务, 你可以看到最终结果
Gulp 还提供了一个名为 watch()
的方法,可以自动检查指定的资源(文件)的变化。这样就可以在文件发生变化时自动执行特定的任务,不必每次修改了文件就要回到命令行手动执行 gulp
.
gulp.watch('./js/*.js', ['js']);
这行代码执行时, Gulp 会持续监控 ./js/ 目录下所有的 js 文件,一旦文件发生变化,就会自动重新执行 "js" 任务来合并和压缩文件。当然,这行代码通常也要放到某个任务中去运行。
转到 Gulp.js
在我开始使用 Grunt 之前的几年里,一直是使用 涛哥 开发的 CssGaga 来做前端构建工具。这是当时我们工作标准流程的一部分,它非常强大。
后来从 isux 转岗到 TGideas, 工作流程发生了巨大的变化,同时我在 Windows / Linux / Mac 不同平台下工作的时间也越来越多,于是转向了 Grunt. 与 CssGaga 相比, Grunt 需要自己去寻找需要的插件,在每个项目中进行适当的配置来完成构建工作,但是它跨平台、按需组合功能的特性较好地满足了我的需要。之后又听说过、尝试过一些前端构建工具,但都没有让我放弃 Grunt.
第一次看到 Gulp 的介绍时,就被它的配置语法所吸引。因为对于任何一个接触过 Node.js 的人来说,这语法是在是太舒服了。一看就懂,看一遍就会,不是吗?暂时来说,它的插件数量还没有 Grunt 那么多那么全面,不过日常的前端任务,还是都涵盖了,而且有一些实现得比 Grunt 平台上的更棒。而且它的插件库也不断在增长,尤其是现在有这么多开发者对它有兴趣,相信它会得到快速的发展。
如果你还没有尝试过,不妨尝试一下。