zoukankan      html  css  js  c++  java
  • 教你写gulp plugin

      前端开发近两年工程化大幅飙升。随着Nodejs大放异彩,静态文件处理不再需要其他语言辅助。主要的两大工具即为基于文件的grunt,基于流的gulp。简单来说,如果需要的只是文件处理,gulp绝对首选。如果是其他依赖于文件的任务管理,例如测试(karmamocha),推荐使用grunt

      gulp常用api:

    gulp.src(globs[,options])
    
    gulp.dest(path[,options])
    
    gulp.task(name[,deps], fn)
    
    gulp.watch(glob [, opts], tasks) or gulp.watch(glob [, opts, cb])
    
    gulp.start(["param"]);

    一、gulp plugin开发依赖

      就插件开发难度而言,gulp远低于grunt。如果你只关注如何处理文件,而不关注细节,那么需要依赖Nodejs Transform stream的实现。可以使用官方推荐的through2,但推荐使用through-gulp。后者是基于前者,为gulp插件编写精简优化重写而来。千万不要使用through,这个包时间久远,长时间没有维护,而且部分mock实现的功能,到nodejs 0.10.x已经原生支持。如果只是想学习如何编写gulp插件,through-gulp更适合。 

      through-gulp: https://github.com/bornkiller/through-gulp
      through2: https://github.com/rvagg/through2.git
      through: https://github.com/dominictarr/through

    二、利用through-gulp开发gulp plugin

     依赖API

    var through = require('through-gulp');
    var stream = through(transformFunction, flushFunction);

     结构 

    // PLUGIN_NAME: sample 
    var through = require('through-gulp');
     
    function sample() {
      //通过through创建流stream
      var stream = through(function(file, encoding,callback) {
      
        //进程文件判断
        if (file.isNull()) {
     
        }
        if (file.isBuffer()) {
     
        }
        if (file.isStream()) {
     
        }
        // just pipe data next, or just do nothing to process file later in flushFunction 
        // never forget callback to indicate that the file has been processed. 
          this.push(file);
          callback();
        },function(callback) {
          // just pipe data next, just callback to indicate that the stream's over 
          this.push(something);
          callback();
        });
     
      //返回这个流文件
      return stream;
    };
     
    // exporting the plugin  
    module.exports = sample;
    

     这里

    through(function(file, encoding,callback){})发现file是一个对象,含有如下许多属性,但是我们常用的通常是file.path获取文件路径,file.contents获取文件内容

    
    

     使用:

    var gulp = require('gulp');
    var sample = require('sample');
    gulp.task('sample', function() {
      return gulp.src(['source file'])
        .pipe(sample())
        .pipe(gulp.dest('file destiny'))
    });

      从以上我们可以看到,through-gulp插件写法,其实就是读取转换流,存储流,导出流的一个过程(一个文件一个文件的过去),如果我们不需要导出流进行链式写法,其实直接module.exports = sample就可以直接单向使用。

      下面来看一下简单的 gulp-pf-replace插件,理解原理:

    //Gulp默认使用buffer
    
    var through = require("through-gulp");  //引入gulp插件模块
    var fs = require("fs");
    var http = require("http");
    var request = require("request");
    var path = require("path");
    var source = require('vinyl-source-stream'); //常规流转换为gulp支持的Vinyl文件格式
    var gutil = require('gulp-util'); 
     //gulp多功能的插件,可以替换扩展名,log颜色日志,模板
     
    var chalk = require('chalk'); //设置颜色
    chalk.blue('Hello world!');
    
    // 类型判断
    function isType(type){
        return function(o){
            return Object.prototype.toString.crall(o) === '[object ' + type + ']';
        }
    }
    
    var isString = isType("String");
    var isObject = isType("Object");
    var isArray = isType("Array");
    
    gutil.log('stuff happened', 'Really it did', gutil.colors.magenta('123'));
    
    var i=0;
    //gulp插件原理就是一个流进入,流处理完出来
    function replace(modReplace) {
    	
      //通过through创建流stream
      var stream = through(function(file, encoding,callback) {
    	//file为对象,含有path,clone,pipe,inspect,history,isNull,isDirectory 等,常用的是path
    	//console.log(isObject(file));
    	
        //进程文件判断
        if (file.isNull()) {
    		throw "NO Files,Please Check Files!"
        }
    	
    	//buffer对象可以操作
        if (file.isBuffer()) {
    		//拿到单个文件buffer
    		var content = modReplace(file.contents.toString("utf-8"));
    		
    		//console.log(contents);
    		file.contents = new Buffer(content,"utf-8");
    		//可以通过buffer.toString("utf-8")转换成字符串
    		//contents = file.contents.toString("utf-8")
        }
    	
    	//stream流是不能操作的,可以通过fs.readFileSync
        if (file.isStream()) {
    		//同步读取
    		 var content = modReplace(fs.readFileSync(file.path).toString("utf-8"));
    		 file.contents = new Buffer(content,"utf-8");
        }
    	
        // just pipe data next, or just do nothing to process file later in flushFunction 
        // never forget callback to indicate that the file has been processed. 
          this.push(file);
          callback();
    	  i++;
        },function(callback) {
    		gutil.log( gutil.colors.red(i) ,  gutil.colors.green("已经处理完毕!"));
          // just pipe data next, just callback to indicate that the stream's over 
         // this.push(something);
          callback();
        });
    	
      //返回这个流文件
      return stream;
    };
     
    // 导出插件 
    module.exports = replace;
    

      使用:

    gulp.task("pfDefault",function(){
        return gulp.src("./tianzun/*.+(html|htm)",{buffer: true})
                .pipe(pfDefault(ypReplace))
                .pipe(gulp.dest("./out"))
           .on("finish",function(){
              console.log("处理完成")
           }) });
    //替换方法 function ypReplace(data){ return data.replace(/helloword/,"123") }

      上面注解比较多,应该大多数人看得懂,这里我就不再做解释。

    三、利用through2开发gulp plugin

      结构如下:

    // through2 是一个对 node 的 transform streams 简单封装
    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;
    }
    
    // 插件级别函数 (处理文件)
    function gulpPrefixer(prefixText) {
    
      if (!prefixText) {
        throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
      }
      prefixText = new Buffer(prefixText); // 预先分配
    
      // 创建一个让每个文件通过的 stream 通道
      return through.obj(function(file, enc, cb) {
        if (file.isNull()) {
          // 返回空文件
          cb(null, file);
        }
        if (file.isBuffer()) {
          file.contents = Buffer.concat([prefixText, file.contents]);
        }
        if (file.isStream()) {
          file.contents = file.contents.pipe(prefixStream(prefixText));
        }
    
        cb(null, file);
    
      });
    
    };
    
    // 暴露(export)插件主函数
    module.exports = gulpPrefixer;

    推荐阅读:

      Gulp思维——Gulp高级技巧  理解gulp底层处理是buffer、还是Vinyl文件格式流

      编写gulp指导

      through-gulp插件

       从零单排之gulp实战 理解gulp的相关原理

  • 相关阅读:
    【RS】Automatic recommendation technology for learning resources with convolutional neural network
    卷积神经网络的入门
    Debug 路漫漫-10:AttributeError: 'Embedding' object has no attribute 'get_shape'
    Debug 路漫漫-09:构建CNN时维度不一致问题
    Debug 路漫漫-08:Keras 版本升级函数变换导致的问题
    springboot 过滤器、拦截器、消息转换器、切片执行顺序 及区别
    java InputStream读取数据问题
    Springboot 2-OAuth 2修改登录加密方式
    Spring Boot Security Oauth2之客户端模式及密码模式实现
    oauth2.0通过JdbcClientDetailsService从数据库读取相应的配置
  • 原文地址:https://www.cnblogs.com/pingfan1990/p/4809128.html
Copyright © 2011-2022 走看看