Gulp使用入门
提到 Gulp,不得不说到的是较早的 JS 项目自动化构建工具——Grunt。
前端开发过程中,特别是最近几年多了 CoffeeScript、Sass、Less 等一些预编译语言,很多代码每次写完需要手动到工作目录去编译才能执行。此外,项目预发布时候需要进行 js、css 文件合并、压缩、重命名等操作,实在是很繁琐。此前很多工程师使用的是 Makefile 构建项目,但是这要求需要一定Linux基础,而且编写配置文件会增大非常多工作量, Grunt 的出现,解放了前端工程师的双手=_=
Grunt 通过 CLI 配合配置文件 gruntfile.js 去完成自动化构建任务,社区有非常多的 Grunt 插件,比如 concat(合并文件)、 uglify(js压缩),只需要在 gruntfile.js 中配置好路径等一些参数,运行以下命令就可以自动执行。
grunt takeName
Gulp是一款 The streaming build system(流式构建系统),如果说 Grunt 是基于 gruntfile.js 任务执行器,Gulp 就是基于 NodeJS 的文件流任务执行器,比起 Grunt 有如下特点
-
使用方便通过代码优于配置的策略,Gulp 可以让简单的任务简单,复杂的任务更可管理。
-
构建快速通过流式操作,减少频繁的 IO 操作,更快地构建项目。
-
插件高质Gulp 有严格的插件指导策略,确保插件能简单高质的工作。
-
易于学习少量的API,掌握 Gulp 可以毫不费力。构建就像流管道一样,轻松加愉快。
Gulp实现
Gulp 主要 API 为 gulp.src(使用glob模式匹配获得文件流集)、gulp.dest(输出gulp文件流集到指定路径,路径指定相对于gulpfile.js配置文件)、gulp.watch(监听glob模式匹配的文件集,有改动时执行相应gulp任务),如图:
orchestrator
译作管弦乐演奏家,大多数就是一个老头拿着个小棍的形象,就像这样:
一个npmjs模块,就是一个以最大并发方式去排序或执行一系列的任务。这些任务就是我们之后会用到的 Gulp 任务,比如说 css 命名的任务,里面包括css的浏览器前缀添加、合并、压缩等操作。orchestrator 通过实例化一个对象,在对象上调用 add 来添加特定命名的任务、添加任务时候可以声明任务依赖,比如:
var Orchestrator = require('orchestrator'); var orchestrator = new Orchestrator(); orchestrator.add('thing1', function(){ // do stuff }); orchestrator.add('thing2', function(){ // do stuff }); orchestrator.add('mytask', ['thing1','thing2'], function() { // Do stuff });
以上代码,添加了3个 Gulp 任务,mytask 任务依赖于 thing1 和 thing2 ,即必须执行完后面两个任务,mytask才能执行,通过任务依赖,很容易理清和构建任务时候的执行顺序。需要注意的是,在填写 do stuff 时候,要确保其返回一个 promise 或者是 event stream(最常用),比如一个简单的任务是这样定义的:
var map = require('map-stream'); orchestrator.add('thing4', function(){ var stream = map(function (args, cb) { cb(null, args); }); // do stream stuff return stream; });
或则是返回一个 promise:
var Q = require('q'); orchestrator.add('thing3', function(){ var deferred = Q.defer(); // do async stuff setTimeout(function () { deferred.resolve(); }, 1); return deferred.promise; });
orchestrator 调用 start 来执行特定名称的任务,可一次执行多个:
orchestrator.start('one', 'two');
以上两个是 orchestrator 最常用的用于实现 Gulp 的函数,除此之外,还有任务检测,任务暂停,任务事件监听,想详细了解可访问npmjs: https://www.npmjs.org/package/orchestrator
vinyl-fs
这是 Gulp 采用的一个虚拟文件系统,可以读取 glob 模式匹配到的文件并转成文件流,可以获取文件流并转成文件集。其中 vinyl-fs 使用 vinyl 虚拟文件描述类,来对 glob 匹配到的文件进行描述,所谓的描述,只是简单的文件名与路径,以及文件内容,可以说是一个文件的封装,可以看看 vinyl 是如何描述一个或一组文件的:
var File = require('vinyl'); var coffeeFile = new File({ cwd: "/", base: "/test/", path: "/test/file.coffee", contents: new Buffer("test = 123") });
除了 vinyl ,vinyl-fs 还需要依赖 glob-stream 读写文件流,如图:
glob-stream
大家可能有疑问,读写文件流,为什么不用 nodejs 内核的 steam 类来读写呢,骚安勿燥,Gulp 既然是基于 nodejs 构建,最终自然也是依赖 nodejs 内核实现它的功能的。
只是,stream 类读取文件流只针对一个文件路径,glob-stream 就是实现从获取 glob 模式匹配文件集,到转换成文件路径,再到读取,还是有一段距离的。如图:
glob-stream 通过 minimatch 来进行 glob 模式匹配,通过其他路径模块,获得一组文件路径,然后就是 ordered-read-streams 发光发热时候啦,对这组文件路径一个个地读啊,然后就获得一组文件流啦。
好啦,终于分析完 Gulp 的实现,通过对其中模块的阅读,其实 Nodejs 模块有点像乐高积木,内核给出的就是最基本的积木啦,不过你可以无限次使用它们,来堆出一个个小的物体,通过小小的物体组合,来组成非常徇丽多姿的乐高作品啦~
当然,也是有一些 c++ 实现的nodejs模块,主要是用于一些需要高性能运算的地方,不过npmjs.org上介绍到的模块,大部分的依赖都是基于 nodejs 内核实现滴。