zoukankan      html  css  js  c++  java
  • Gulp:插件编写入门

    之前挖了个坑,准备写篇gulp插件编写入门的科普文,之后迟迟没有动笔,因为不知道该肿么讲清楚Stream这货,毕竟,gulp插件的实现不像grunt插件的实现那么直观。

    好吧,于是决定单刀直入了。文中插件示例可在这里找到:https://github.com/chyingp/gulp-preprocess

    写在前面

    我们来看看下面的gruntfile,里面用到了笔者刚写的一个gulp插件gulp-preprocess。好吧,npm publish的时候才发现几个月前就被抢注了。为什么星期天晚上在 http://npmjs.org/package/ 上没有搜到 TAT

    这个插件基于preprocess这个插件,插件使用方法请自行脑补。本文就讲解下如何实现 gulp-preprocess 这个插件

    var gulp = require('gulp'),
        preprocess = require('gulp-preprocess');
    
    gulp.task('default', function() {
        gulp.src('src/index.html')
            .pipe(preprocess({USERNAME:'程序猿小卡'}))
            .pipe(gulp.dest('dest/'));
    });
    

    进入实战

    关键代码

    我们来看下最关键的几行代码。可以看到,上文的 preprocess() 的作用就是返回一个定制的 Object Stream ,这是实现gulp的流式操作必需的,其他gulp插件也大同小异。

    gulp-preprocess/index.js

    module.exports = function (options) {
        return through.obj(function (file, enc, cb) {
            // 主体实现忽略若干行
        });
    };
    

    接着,看下具体实现。实际上代码很短

    引入依赖

    首先,引入插件的依赖项。其中:

    • gutil:按照gulp的统一规范打印错误日志
    • through2:Node Stream的简单封装,目的是让链式流操作更加简单
    • preprocess:文本预处理器,主要就是文本替换啦
    'use strict';
    var gutil = require('gulp-util');
    var through = require('through2');
    var pp = require('preprocess');
    

    核心逻辑

    其次,定义gulp-preprocess的主体代码。没错,就是下面这么短的代码。代码结构也比较清晰,下面还是简单做下分解介绍。

    module.exports = function (options) {
        return through.obj(function (file, enc, cb) {
            if (file.isNull()) {
                this.push(file);
                return cb();
            }
    
            if (file.isStream()) {
                this.emit('error', new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
                return cb();
            }
    
            var content = pp.preprocess(file.contents.toString(), options || {});
            file.contents = new Buffer(content);
    
            this.push(file);
    
            cb();
        });
    };
    

    核心代码分解

    还是直接上代码,在关键位置加上注释。对 through2 不熟悉的童鞋可以参考这里

    module.exports = function (options) {
        return through.obj(function (file, enc, cb) {
    
            // 如果文件为空,不做任何操作,转入下一个操作,即下一个 .pipe()
            if (file.isNull()) {
                this.push(file);
                return cb();
            }
    
            // 插件不支持对 Stream 对直接操作,跑出异常
            if (file.isStream()) {
                this.emit('error', new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
                return cb();
            }
    
            // 将文件内容转成字符串,并调用 preprocess 组件进行预处理
            // 然后将处理后的字符串,再转成Buffer形式
            var content = pp.preprocess(file.contents.toString(), options || {});
            file.contents = new Buffer(content);
    
            // 下面这两句基本是标配啦,可以参考下 through2 的API
            this.push(file);
    
            cb();
        });
    };
    

    写在后面

    要把gulp插件内部实现的原理讲透不是件容易的事情,因为实现还是比较复杂的,首先需要对Buffer、Stream 有一定的了解,包括如何通过Node暴露的API对Stream进行定制化。可以参考笔者的另一篇随笔《gulp.src()内部实现探究》,虽然也只是讲了很小的一部分。

  • 相关阅读:
    C语言预处理
    C语言结构体对齐
    C语言共用体、大小端、枚举
    C语言内存分配方法。
    C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用
    C语言中函数的传入值与传出值
    #define与typedef在重定义类型中的区别
    宏定义在位运算中的运用
    wait函数
    exit()与_exit()区别
  • 原文地址:https://www.cnblogs.com/chyingp/p/writting-gulp-plugin.html
Copyright © 2011-2022 走看看