前端開發近兩年工程化大幅飙升。随着
Nodejs
大放異彩,靜态檔案處理不再需要其他語言輔助。主要的兩大工具即為基于檔案的
grunt
,基于流的
gulp
。簡單來說,如果需要的隻是檔案處理,
gulp
絕對首選。如果是其他依賴于檔案的任務管理,例如測試(
karma
,
mocha
),推薦使用
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的相關原理
轉載于:https://www.cnblogs.com/pingfan1990/p/4809128.html