kangkangblog

Menu

gulp插件踩坑

如你般阳光明媚

本篇是简述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文件可以通过三种不同形式来访问文件内容:

插件类型

那么我们的插件应该一般是有两种形式,一种是基于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 有很多不懂的不会的,期待慢慢去完整自己

— 于 共写了3723个字
— 文内使用到的标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注