gulp tips
这个也是系列文章中得一篇。
gulp流为何流
gulp是基于流进行操作的,整个插件都是通过pipe()
函数来赋予。gulp插件每次读取和返回都是一个object mode
流,使用gulp.src()
读取文件时,就会转换成viny File
的格式。插件读入viny File objects
,然后在输出viny File objects
。一般我们叫它transform stream
。
A “transform” stream is a duplex stream where the output is causally connected in some way to the input, such as a zlib stream or a crypto stream.———node.js doc
transform stream
就是一个可读可写duplex stream
,好吧,我叫它‘双工’。可以理解为,它不保存数据,只是处理经过的数据。而且gulp就是利用这一点,gulp的插件就是如此作为一个transform stream
来处理经过的数据。
vinyl File Content
vinyl
通常有三种形式来展现内容:Stream,Buffer,Empty。
一般的插件都支持Buffer,当然最好是两者都支持。但是由于某些操作,例如js压缩等,用stream对content进行操作很困难,因为这个需要对全局的content有个掌握才能进行压缩,不然会出问题的。所以当进行的操作需要对全局有所掌握才能进行的,最好使用Buffer。
vinyl File是怎么样的
最简单的一个例子:
var File = require('vinyl');
var coffeeFile = new File({
cwd: "/",
base: "/test/",
path: "/test/file.coffee",
contents: new Buffer("test = 123")
});
每个File都有个cwd
、base
、path
、contents
属性。当插件进行操作时就是封装成一个transform stream
,例如我写的gulp-react-native-css:
var through = require("through2"),
gutil = require("gulp-util"),
parseCss = require('./lib/parseCss');
var ext = gutil.replaceExtension;
module.exports = function () {
"use strict";
function reactNativeCss(file, enc, callback) {
/*jshint validthis:true*/
// Do nothing if no contents
if (file.isNull()) {
this.push(file);
return callback();
}
if (file.isStream()) {
// accepting streams is optional
this.emit("error",
new gutil.PluginError("gulp-react-native-css", "Stream content is not supported"));
return callback();
}
// check if file.contents is a `Buffer`
if (file.isBuffer()) {
var source = file.contents.toString();
var style = parseCss(source.replace(/\r?\n|\r/g, ""));
var prefix = "module.exports =";
file.contents = new Buffer(prefix + style);
file.path = ext(file.path, '.js');
this.push(file);
}
return callback();
}
return through.obj(reactNativeCss);
};
through2这个库实现了对node stream的简单封装,对于生成一个双工的stream很方便。因为gulp采用的是object mode,所以直接调用through.obj()
就ok了。而上面的reactNativeCss
就作为一个transform函数了。
有关transform stream的知识,可以看node.js stream doc。其中提到:
Rather than implement the _read() and _write() methods, Transform classes must implement the _transform() method, and may optionally also implement the _flush() method. (See below.)
而上面例子中得reactNativeCss
就是赋给了_transform
。也就是这个函数:transform._transform(chunk, encoding, callback)
。