Gulp使用入门

jopen 9年前

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任务),如图:

Gulp使用入门

orchestrator

译作管弦乐演奏家,大多数就是一个老头拿着个小棍的形象,就像这样:

Gulp使用入门

一个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 读写文件流,如图:

Gulp使用入门

glob-stream

大家可能有疑问,读写文件流,为什么不用 nodejs 内核的 steam 类来读写呢,骚安勿燥,Gulp 既然是基于 nodejs 构建,最终自然也是依赖 nodejs 内核实现它的功能的。

只是,stream 类读取文件流只针对一个文件路径,glob-stream 就是实现从获取 glob 模式匹配文件集,到转换成文件路径,再到读取,还是有一段距离的。如图:

Gulp使用入门

glob-stream 通过 minimatch 来进行 glob 模式匹配,通过其他路径模块,获得一组文件路径,然后就是 ordered-read-streams 发光发热时候啦,对这组文件路径一个个地读啊,然后就获得一组文件流啦。

好啦,终于分析完 Gulp 的实现,通过对其中模块的阅读,其实 Nodejs 模块有点像乐高积木,内核给出的就是最基本的积木啦,不过你可以无限次使用它们,来堆出一个个小的物体,通过小小的物体组合,来组成非常徇丽多姿的乐高作品啦~

当然,也是有一些 c++ 实现的nodejs模块,主要是用于一些需要高性能运算的地方,不过npmjs.org上介绍到的模块,大部分的依赖都是基于 nodejs 内核实现滴。