教你寫gulp plugin

  前端開發近兩年工程化大幅飆升。隨着Nodejs大放異彩,靜態文件處理再也不須要其餘語言輔助。主要的兩大工具即爲基於文件的grunt,基於流的gulp。簡單來講,若是須要的只是文件處理,gulp絕對首選。若是是其餘依賴於文件的任務管理,例如測試(karmamocha),推薦使用grunthtml

  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"]);

1、gulp plugin開發依賴

  就插件開發難度而言,gulp遠低於grunt。若是你只關注如何處理文件,而不關注細節,那麼須要依賴Nodejs Transform stream的實現。可使用官方推薦的through2,但推薦使用through-gulp。後者是基於前者,爲gulp插件編寫精簡優化重寫而來。千萬不要使用through,這個包時間久遠,長時間沒有維護,並且部分mock實現的功能,到nodejs 0.10.x已經原生支持。若是隻是想學習如何編寫gulp插件,through-gulp更適合。 node

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

2、利用through-gulp開發gulp plugin

 依賴APIgithub

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

 結構 npm

// 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;

 這裏gulp

through(function(file, encoding,callback){})發現file是一個對象,含有以下許多屬性,可是咱們經常使用的一般是file.path獲取文件路徑,file.contents獲取文件內容

 

 使用:api

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就能夠直接單向使用。app

  下面來看一下簡單的 gulp-pf-replace插件,理解原理:dom

//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") }

  上面註解比較多,應該大多數人看得懂,這裏我就再也不作解釋。

3、利用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的相關原理

相關文章
相關標籤/搜索