2

gulp插件踩坑

 3 years ago
source link: https://zwkang.com/?p=447
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如你般阳光明媚

本篇是简述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 有很多不懂的不会的,期待慢慢去完整自己

Comments

发表评论 取消回复

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

评论

姓名 *

电子邮件 *

站点

在此浏览器中保存我的名字、电邮和网站。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK