gulp plugin開發

前言

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

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

gulp plugin開發結構

// PLUGIN_NAME: sample
var through = require('through-gulp');

function sample() {
  // creating a stream through which each file will pass
  var stream = through(function(file, encoding,callback) {
      // do whatever necessary to process the file 
      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();
    });

  // returning the file stream
  return stream;
};

// exporting the plugin 
module.exports = sample;

then use the plugin with gulpgit

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

這個sample是一個plugin的基本模板,一般的內容處理包裹與以下所示部分,因此一般關注重點也在此處。。github

if (file.isBuffer()) {
  //文件處理
}

須要特別注意的是,若是你須要處理的不一樣文件之間沒有任何依賴,在第一個函數函數內部處理完後,進行以下調用,便可將該文件的處理結果傳遞給下一個插件。這種狀況下,能夠缺省第二個參數flushFunctionnpm

if (file.isBuffer()) {
  // 文件處理
  var data = fileProcess(file);
  // 傳遞處理後數據給下一個插件
  this.push(data); 
  // 聲明該文件處理完畢
  callback();
}

若是須要處理的不一樣文件之間存在依賴,例如文件合併,須要全部文件所有讀完以後再處理,那麼第一個參數transformFunction將每次傳遞進來的數據保存在內存中(絕對不要在這裏調用this.push()方法),第二個參數flushFunction統一作處理後,再傳遞給下一個插件。json

// transformFunction
var fileStorage = [];
if (file.isBuffer()) {
  // 文件處理
  var data = fileProcess(file);
  // 保存傳遞進來的數據
  fileStorage.push(data); 
  // 聲明該文件處理完畢
  callback();
}
// flushFunction
function(callback) {
  var result = '';
  var final = null;
  fileStorage.foreach(function(file, key) {
    result += file.contents.toString();
  })
  final = new Buffer(result);
  this.push(final);
  callback();
}

gulp優點淺析

  • 基於stream
    grunt基於文件的機制,致使了任務之間沒有信息傳遞。舉簡單例子說明,任務流程基本上打開文件、處理文件、保存文件、關閉文件,而後執行繼續向後執行任務。每個任務都須要作重複的打開、保存、關閉操做無疑影響效率。gulp的特色在於單入口模式,文件打開、保存、關閉均一次,從內存拿數據,確定比從硬盤拿數據快。gulp

  • 配置項精簡
    grunt的配置項繁雜算是公認的弊病,options嵌套表現尚可,擴展模式與非擴展模式,並且自帶concat行爲有時讓人難以理解。以coffee script的編譯舉例dom

// Gruntfile.js
// 包裝函數
module.exports = function(grunt) {
    // 任務配置
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        coffee: {
            options: {
                bare: true,
                sourceMap: true
            },

            compile: {
                files: {
                    'storage-coffee/judge.js': ['storage-coffee-source/judge.coffee'],
                    'storage-coffee/storage.js': ['storage-coffee-source/storage.coffee']
                }
            }
        }
    // 任務加載
    grunt.loadNpmTasks('grunt-contrib-coffee');
};
// gulpfile.js
var gulp = require('gulp');
var gutil = require('gulp-util');
var coffee = require('gulp-coffee');
var sourcemaps = require('gulp-sourcemaps');

gulp.task('coffee', function() {
  gulp.src('storage-coffee-source/*.coffee')
    .pipe(sourcemaps.init())
    .pipe(coffee({bare: true}).on('error', gutil.log))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('storage-coffee'));
});
  • 插件任務明確
    grunt插件基本上都是多功能,如上所示,grunt-contrib-coffee附帶sourcemap功能,而gulp-coffee則只負責編譯,sourcemap交由其餘插件處理。私覺得,功能單一化能夠更好地組合使用。

後記

就插件編寫的角度而言,through-gulp方法更加精煉,是爲gulp插件開發而生,而不是爲了node stream開發而生,因此無需理會through2晦澀的文檔,以前有一個不幸的地方,在gulp插件開發的單元測試中,經常使用的assert-stream是基於through2的,可是不影響大局。如今基於through-gulp編寫gulp插件測試的模塊stream-assert-gulp,目的在於爲gulp插件編寫與測試下降難度。基於前二者,編寫了gulp-requirejs-optimizer插件做爲使用requirejs做爲AMD加載器的優化工做,基本可用。函數

相關文章
相關標籤/搜索