美文网首页
如何写一个gulp插件?

如何写一个gulp插件?

作者: 风之化身呀 | 来源:发表于2017-12-24 17:07 被阅读36次

    1、基础储备

    • Node常用的三种流:Readable、Writable、Transform
    • 流之间用pipe来传递,pipe是流的实例方法
    • Transform流通常用第三方模块through2来创建
    • 常用Node的fs模块中fs.createReadStream(路径)创建Readable流,fs.createWriteStream(路径)创建Writable流
    • Buffer类数据buffer可通过buffer.toString('utf-8')转为字符串String类型

    2、基本结构

    // 1、引入模块
    var through = require('through2');
    var gutil = require('gulp-util');
    var PluginError = gutil.PluginError;
    const PLUGIN_NAME = 'gulp-prefixer';
    
    function prefixStream(prefixText) {
      var stream = through();
      stream.write(prefixText);
      return stream;
    }
    
    // 2、编写插件主函数 (处理文件)
    function gulpPrefixer(prefixText) {
      if (!prefixText) {
        throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
      }
      prefixText = new Buffer(prefixText); // 将prefixText以二进制形式存储
    
      // 创建一个让每个文件通过的 stream 通道
      var stream = through.obj(function(file, enc, cb) {
        if (file.isBuffer()) {
          this.emit('error', new PluginError(PLUGIN_NAME, 'Buffers not supported!'));
          return cb();
        }
        if (file.isStream()) {
          // 定义转换内容的 streamer
          var streamer = prefixStream(prefixText);
          // 从 streamer 中捕获错误,并发出一个 gulp的错误
          streamer.on('error', this.emit.bind(this, 'error'));
          // 开始转换
          file.contents = file.contents.pipe(streamer);
        }
    
        // 确保文件进去下一个插件
        this.push(file);
        // 告诉 stream 转换工作完成
        cb();
      });
    
      // 返回文件 stream
      return stream;
    }
    
    // 3、暴露(export)插件的主函数
    module.exports = gulpPrefixer;
    

    3、主函数编写

    • 判断插件的输入类型:Buffer Or Stream
      Buffer类一般指该插件接收的数据是Buffer;Stream类该插件接收的数据是Stream,在使用gulp时,由gulp.src读取的文件传递给后续插件时默认都是Buffer,若想支持Stream,需显示调用gulp.src(路径,{buffer:false})。从大部分gulp插件使用方式来看,处理Buffer的情形占大多数。
    file.isStream()
    
    • file对象
      保存读取的文件信息,file.contents是主要内容,也是一个流对象
    • through2
      通过through或through.obj创建的transform对象起着承前启后的作用。
      承前:通过file对象获取上一个pipe来的数据
      启后:对file对象进行改造,并通过this.push(file)和cb()向后一个pipe传递数据

    4、插件实例

    var through = require('through2');
    var gutil = require('gulp-util');
    var applySourceMap = require('vinyl-sourcemaps-apply');
    var path = require('path');
    var merge = require('merge');
    
    var PluginError = gutil.PluginError;
    
    module.exports = function (opt) {
      function replaceExtension(path) {
        path = path.replace(/\.coffee\.md$/, '.litcoffee');
        return gutil.replaceExtension(path, '.js');
      }
    
      function transform(file, enc, cb) {
        if (file.isNull()) return cb(null, file);
        if (file.isStream()) return cb(new PluginError('gulp-coffee', 'Streaming not supported'));
    
        var data;
        var str = file.contents.toString('utf8');  // 1、这里开始,str就都是字符串了,可以采用正则进行处理了!
        var dest = replaceExtension(file.path);
    
        var options = merge({  // 2、合并选项
          bare: false,
          coffee: require('coffeescript'),
          header: false,
          sourceMap: !!file.sourceMap,
          sourceRoot: false,
          literate: /\.(litcoffee|coffee\.md)$/.test(file.path),
          filename: file.path,
          sourceFiles: [file.relative],
          generatedFile: replaceExtension(file.relative)
        }, opt);
    
        try {
          data = options.coffee.compile(str, options);
        } catch (err) {
          return cb(new PluginError('gulp-coffee', err));
        }
    
        if (data && data.v3SourceMap && file.sourceMap) {
          applySourceMap(file, data.v3SourceMap);
          file.contents = new Buffer(data.js);   
        } else {
          file.contents = new Buffer(data);      // 3、将处理后的字符串再转回buffer类型
        }
    
        file.path = dest;
        cb(null, file);                              //  4、将处理后的文件向下一级传输
      }
    
      return through.obj(transform);
    };
    

    相关文章

      网友评论

          本文标题:如何写一个gulp插件?

          本文链接:https://www.haomeiwen.com/subject/uujhgxtx.html