如你般阳光明媚
本篇是简述gulp插件
http://www.gulpjs.com.cn/docs/writing-a-plugin/ 首先看官方对插件的描述。 gulp插件的话认真看看有node基础鼓捣下半天也能做个小插件
stream
transform streams (有时候也叫做 through streams)。transform streams 是可读又可写的,它会对传给它的对象做一些转换的操作。 transform stream 可读可写 可以处理流经他的data
stream hanbook
根据官方的推荐,恶补了一下stream hanbook 以下是简化后的内容 流大概有五种 readable,writable,transform,duplex以及"classic" 都是通过pipe方法进行输入输出 它仅仅是接受一个源头src并将数据输出到一个可写的流dst中: src.pipe(dst) 官方文档指出gulp插件总是返回一个object mode形式的stream来做这些事情 通常被叫做transform streams 这是handbook对transform stream的描述 transform流想象成一个流的中间部,它可以读也可写,但是并不保存数据,它只负责处理流经它的数据。 流是node里面的一个重要概念 node是能够很好的处理io,所以掌握stream跟buffer对于学习node很重要
gulp插件
gulp 插件总是返回一个 object mode 形式的 stream 来做这些事情: 接收 vinyl File 对象 输出 vinyl File 对象
Vinyl
Vinyl文件可以通过三种不同形式来访问文件内容:
- Streams
- Buffers
- 空 (null) (对于删除, 清理, 等操作来说,会很有用,因为这时候内容是不需要处理的。(null时即停下))
插件类型
那么我们的插件应该一般是有两种形式,一种是基于Buffer一种是基于Stream
// 插件级别的函数(处理文件)
function gulpPrefixer(prefixText) {
if (!prefixText) {
throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
}
prefixText = new Buffer(prefixText); // 提前分配
// 创建一个 stream 通道,以让每个文件通过
var stream = through.obj(function(file, enc, cb) {
// 判断类型
if (file.isStream()) {
this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!'));
return cb();
}
if (file.isBuffer()) {
file.contents = Buffer.concat([prefixText, file.contents]);
}
// 确保文件进入下一个 gulp 插件
this.push(file);
// 告诉 stream 引擎,我们已经处理完了这个文件
cb();
});
// 返回文件 stream
return stream;
};
贴上官网的一个示例一步步得解析 首先这个官网示例的插件是合并一些内容。 所以第一步需要传参进这个插件处理函数做合并操作 第一步判断传参是否为空,为空的话就用PluginError抛出错误 而不是显式得抛出错误 然后是分配转换Buffer字节
buffer简单插件
through2是对Stream.Transform的封装 一般gulp的插件都会用through2,这是因为gulp使用了vinyl-fs,而vinyl-fs使用了through2。 然后是判断这个vinyl File 对象stream类型判断
// 官网buffer插件例子
var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;
// 常量
const PLUGIN_NAME = 'gulp-prefixer';
// 插件级别的函数(处理文件)
function gulpPrefixer(prefixText) {
if (!prefixText) {
throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
}
prefixText = new Buffer(prefixText); // 提前分配
// 创建一个 stream 通道,以让每个文件通过
var stream = through.obj(function(file, enc, cb) {
if (file.isStream()) {
this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!'));
return cb();
}
if (file.isBuffer()) {
file.contents = Buffer.concat([prefixText, file.contents]);
}
// 确保文件进入下一个 gulp 插件
this.push(file);
// 告诉 stream 引擎,我们已经处理完了这个文件
cb();
});
// 返回文件 stream
return stream;
};
// 导出插件主函数
module.exports = gulpPrefixer;
官网这个buffer例子使用的是buffer如果为stream的话就抛出错误信息 接着是判断是否为Buffer,为Buffer的话就进行对应的操作这边是用Buffer.concat 对两个buffer进行合并(输入的显然是一个字符串buffer) this.push(file) 显式的压入流中 然后cb告诉stream引擎已经处理完了。 然后返回这个文件stream,继续进行gulp流处理
stream插件
buffer与stream处理模式差不多,差别是一个为buffer一个为stream操作 在gulp创建的时候可以传入一个option Buffer指定true或false从而指定它的处理模式 主要都是操作这个流程。
测试
测试,测试的话,我们留意导出的模块其实就是一个流模块
var assert = require('assert');
var es = require('event-stream');
var File = require('vinyl');
var prefixer = require('../');
describe('gulp-prefixer', function() {
describe('in streaming mode', function() {
it('should prepend text', function(done) {
// 创建伪文件
var fakeFile = new File({
contents: es.readArray(['stream', 'with', 'those', 'contents'])
});
// 创建一个 prefixer 流(stream)
var myPrefixer = prefixer('prependthis');
// 将伪文件写入
myPrefixer.write(fakeFile);
// 等文件重新出来
myPrefixer.once('data', function(file) {
// 确保它以相同的方式出来
assert(file.isStream());
// 缓存内容来确保它已经被处理过(加前缀内容)
file.contents.pipe(es.wait(function(err, data) {
// 检查内容
assert.equal(data, 'prependthisstreamwiththosecontents');
done();
}));
});
});
});
});
导入断言库 导入event-stream模块 导入伪文件模块 导入要测试的gulp插件 对应的一些可以通过官网的注释看清楚。 有时候做测试往往可以让你从另外一个角度更好的清楚自己的代码。
连接travis-ci
CI持续集成,持续集成是软件工程里面一个很重要的点。 它能让我们在修改代码后快速地得到反馈。根据测试更早的发现代码的问题。 github有一个免费的ci travis-ci。
- 用github账号登录后
- 在项目根目录中添加.travis.yml文件后。
- 选择对应项目
- 进行构建
- Status Image的link添加到Readme文件中
sudo: false language: node_js node_js: - "5" - "4" // 简单例子总结
我们通过官网的一个简单的实现解析,可以让我们了解使用gulp的时候是发生了什么。 这让我们可以更好地使用它。可以根据我们自己的需要开发或者寻找对应的插件使用。 然后根据插件制作原理制作一个简单的类似插件体验。 相信这样的一种体验是不错的。
链接
题外话
本文是为了填坑大半个月前的学习成果。 这个月大概去了一趟旅游,很开心。 2017年6月24日21:35:10 有很多不懂的不会的,期待慢慢去完整自己