摘要:我們創(chuàng)建一個(gè)可讀流,并嘗試使用和來(lái)進(jìn)行轉(zhuǎn)換,將最后得到的內(nèi)容交給。它重新使用可讀流中的文件名,然后在必要時(shí)創(chuàng)建文件夾使用。使用常規(guī)可讀流時(shí),你可以監(jiān)聽(tīng)事件來(lái)檢測(cè)數(shù)據(jù)碎片的到來(lái)不同的是,使用會(huì)將轉(zhuǎn)換成的文件對(duì)象重新寫(xiě)入到流中。
本文翻譯自Getting gulpy -- Advanced tips for using gulp.js
感受過(guò)gulp.js帶來(lái)的興奮過(guò)后,你需要的不僅僅是它的光鮮,而是切切實(shí)實(shí)的實(shí)例。這篇文章討論了一些使用gulp.js時(shí)常踩的坑,以及一些更加高級(jí)和定制化的插件和流的使用技巧。
基本任務(wù)gulp的基本設(shè)置擁有非常友好的語(yǔ)法,讓你能夠非常方便的對(duì)文件進(jìn)行轉(zhuǎn)換:
gulp.task("scripts", function() { return gulp.src("./src/**/*.js") .pipe(uglify()) .pipe(concat("all.min.js")) .pipe(gulp.dest("build/")); });
這種方式能夠應(yīng)付絕大多數(shù)情況,但如果你需要更多的定制,很快就會(huì)遇到麻煩了。這篇將介紹這其中的一些情況并提供解決方案。
流不兼容?使用gulp時(shí),你可能會(huì)陷入“流不兼容”的問(wèn)題。這主要是因?yàn)槌R?guī)流和Vinyl文件對(duì)象有差異,或是使用了僅支持buffer(不支持流)庫(kù)的gulp插件與常規(guī)流不兼容。
比如說(shuō),你不能直接將常規(guī)流與gulp和(或)gulp插件相連。我們創(chuàng)建一個(gè)可讀流,并嘗試使用gulp-uglify和gulp-rename來(lái)進(jìn)行轉(zhuǎn)換,將最后得到的內(nèi)容交給gulp.dest()。下面就是個(gè)錯(cuò)誤的例子:
var uglify = require("gulp-uglify"), rename = require("gulp-rename"); gulp.task("bundle", function() { return fs.createReadStream("app.js") .pipe(uglify()) .pipe(rename("bundle.min.js")) .pipe(gulp.dest("dist/")); });
為什么我們不能將可讀流和一個(gè)gulp插件直接相連?gulp難道不就是一個(gè)基于流的構(gòu)建系統(tǒng)嗎?是的,但上面的例子忽視了一個(gè)事實(shí),gulp插件期望的輸入是Vinyl文件對(duì)象。你不能直接將一個(gè)可讀流與一個(gè)以Vinyl文件對(duì)象作為輸入的函數(shù)(插件)相連
Vinyl文件對(duì)象gulp使用了vinyl-fs,它實(shí)現(xiàn)了gulp.src()和gulp.dest()方法。vinyl-fs使用vinyl文件對(duì)象——一種“虛擬文件格式”。如果我們需要將gulp和(或)gulp插件與常規(guī)的可讀流一起使用,我們就需要先把可讀流轉(zhuǎn)換為vinyl。
使用vinyl-source-stream是個(gè)不錯(cuò)的選擇,如下:
var source = require("vinyl-source-stream"), marked = require("gulp-marked"); fs.createReadStream("*.md") .pipe(source()) .pipe(marked()) .pipe(gulp.dest("dist/"));
另外一個(gè)例子首先通過(guò)browserify封裝并最終將其轉(zhuǎn)換為一個(gè)vinyl流:
var browserify = require("browserify"), uglify = require("gulp-uglify"), source = require("vinyl-source-stream"); gulp.task("bundle", function() { return browserify("./src/app.js") .bundle() .pipe(source(‘bundle.min.js)) .pipe(uglify()) .pipe(gulp.dest("dist/")); });
哎呦不錯(cuò)哦。注意我們不再需要使用gulp-rename了,因?yàn)関inyl-source-stream創(chuàng)建了一個(gè)擁有指定文件名的vinyl文件實(shí)例(這樣gulp.dest方法將使用這個(gè)文件名)
gulp.dest這個(gè)gulp方法創(chuàng)建了一個(gè)可寫(xiě)流,它真的很方便。它重新使用可讀流中的文件名,然后在必要時(shí)創(chuàng)建文件夾(使用mkdirp)。在寫(xiě)入操作完成后,你能夠繼續(xù)使用這個(gè)流(比如:你需要使用gzip壓縮數(shù)據(jù)并寫(xiě)入到其他文件)
流和buffer既然你有興趣使用gulp,這篇文章假設(shè)你已經(jīng)了解了流的基礎(chǔ)知識(shí)。無(wú)論是buffer還是流,vinyl的虛擬文件都能包含在內(nèi)。使用常規(guī)可讀流時(shí),你可以監(jiān)聽(tīng)data事件來(lái)檢測(cè)數(shù)據(jù)碎片的到來(lái):
fs.createReadStream("/usr/share/dict/words").on("data", function(chunk) { console.log("Read %d bytes of data", chunk.length); }); > Read 65536 bytes of data > Read 65536 bytes of data > Read 65536 bytes of data > Read 65536 bytes of data > ...
不同的是,使用gulp.src()會(huì)將轉(zhuǎn)換成buffer的vinyl文件對(duì)象重新寫(xiě)入到流中。也就是說(shuō),你獲得的不再是數(shù)據(jù)碎片,而是將內(nèi)容轉(zhuǎn)換成buffer后的(虛擬)文件。vinyl文件格式擁有一個(gè)屬性來(lái)表示里面是buffer還是流,gulp默認(rèn)使用buffer:
gulp.src("/usr/share/dict/words").on("data", function(file) { console.log("Read %d bytes of data", file.contents.length); }); > Read 2493109 bytes of data
這個(gè)例子說(shuō)明了在文件被完整加入到流之前數(shù)據(jù)會(huì)被轉(zhuǎn)換成buffer。
Gulp默認(rèn)使用buffer盡管更加推薦使用流中的數(shù)據(jù),但很多插件的底層庫(kù)使用的是buffer。有時(shí)候必須使用buffer,因?yàn)檗D(zhuǎn)換需要完整的文件內(nèi)容。比如文本替換和正則表達(dá)式的情形。如果使用數(shù)據(jù)碎片,將會(huì)面臨匹配失敗的風(fēng)險(xiǎn)。同樣,像UglifyJS和Traceur Compiler需要輸入完整的文件內(nèi)容(至少需要語(yǔ)法完整的JavaScript字符串)
這就是為什么gulp默認(rèn)使用轉(zhuǎn)換成buffer的流,因?yàn)檫@更好處理。
使用轉(zhuǎn)換成buffer的流也有缺點(diǎn),處理大文件時(shí)將非常低效。文件必須完全讀取,然后才能被加入到流中。那么問(wèn)題來(lái)了,文件的尺寸多大才會(huì)降低性能?對(duì)于普通的文本文件,比如JavaScript、CSS、模板等等,這些使用buffer開(kāi)銷(xiāo)非常小。
在任何情況下,如果將buffer選項(xiàng)設(shè)為false,你可以告訴gulp流中傳遞的內(nèi)容究竟是什么。如下所示:
gulp.src("/usr/share/dict/words", {buffer: false}).on("data", function(file) { var stream = file.contents; stream.on("data", function(chunk) { console.log("Read %d bytes of data", chunk.length); }); }); > Read 65536 bytes of data > Read 65536 bytes of data > Read 65536 bytes of data > Read 65536 bytes of data > ...從流到buffer
由于所需的輸入(輸出)流和gulp插件不盡相同,你可能需要將流轉(zhuǎn)換成buffer(反之亦然)。之前已經(jīng)有過(guò)介紹,大多數(shù)插件使用buffer(盡管他們的一部分也支持流)。比如gulp-uglify和gulp-traceur。你可以通過(guò)gulp-buffer來(lái)轉(zhuǎn)換成buffer:
var source = require("vinyl-source-stream"), buffer = require("gulp-buffer"), uglify = require("gulp-uglify"); fs.createReadStream("./src/app.js") .pipe(source("app.min.js")) .pipe(buffer()) .pipe(uglify()) .pipe(gulp.dest("dist/"));
或者另一個(gè)例子:
var buffer = require("gulp-buffer"), traceur = require("gulp-traceur"); gulp.src("app.js", {buffer: false}) .pipe(buffer()) .pipe(traceur()) .pipe(gulp.dest("dist/"));將buffer轉(zhuǎn)換為流
你也可以使用gulp-streamify或gulp-stream將一個(gè)使用buffer的插件的輸出轉(zhuǎn)化為一個(gè)可讀流。這樣處理之后,跟在使用buffer的插件后面的(只能)使用流的插件也能正常工作了。
var wrap = require("gulp-wrap"), streamify = require("gulp-streamify"), uglify = require("gulp-uglify"), gzip = require("gulp-gzip"); gulp.src("app.js", {buffer: false}) .pipe(wrap("(function(){<%= contents %>}());")) .pipe(streamify(uglify())) .pipe(gulp.dest("build")) .pipe(gzip()) .pipe(gulp.dest("build"));不是所有事都需要插件
雖然已經(jīng)有很多使用且方便的插件,很多任務(wù)以及轉(zhuǎn)換可以不使用插件而輕易完成。插件會(huì)帶來(lái)一些問(wèn)題,你需要依賴(lài)一個(gè)額外的npm模塊,一個(gè)插件接口和(反應(yīng)遲鈍?)的維護(hù)者,等等。如果一個(gè)任務(wù)可以不使用插件而使用原生模塊就能輕易完成,絕大多數(shù)情況下,都建議不要使用插件。能夠理解上面所說(shuō)的概念,并能夠在所處的情況下做出正確的決定,這點(diǎn)非常重要。下面來(lái)看一些例子:
vinyl-source-stream之前的例子中,我們已經(jīng)直接使用了browserify,而不是使用(現(xiàn)已加入黑名單)gulp-browserify插件。這里的關(guān)鍵是使用vinyl-source-stream(或類(lèi)似的庫(kù))進(jìn)行加工,來(lái)將常規(guī)的可讀流輸入使用vinyl的插件。
文本轉(zhuǎn)換另一個(gè)例子就是基于字符串的變換。這里有一個(gè)非常基礎(chǔ)的插件,直接使用了vinyl的buffer:
function modify(modifier) { return through2.obj(function(file, encoding, done) { var content = modifier(String(file.contents)); file.contents = new Buffer(content); this.push(file); done(); }); }
你可以像這樣使用這個(gè)插件:
gulp.task("modify", function() { return gulp.src("app.js") .pipe(modify(version)) .pipe(modify(swapStuff)) .pipe(gulp.dest("build")); }); function version(data) { return data.replace(/__VERSION__/, pkg.version); } function swapStuff(data) { return data.replace(/(w+)s(w+)/, "$2, $1"); }
這個(gè)插件并沒(méi)有完成,而且也不能處理流(完整版本)。然而,這個(gè)例子說(shuō)明,可以很輕易地通過(guò)一些基本函數(shù)來(lái)創(chuàng)建新的變換。through2庫(kù)提供了非常優(yōu)秀的Node流封裝,并且允許像上面那樣使用轉(zhuǎn)換函數(shù)。
任務(wù)流程如果你需要去運(yùn)行一些定制化或動(dòng)態(tài)的任務(wù),了解gulp所使用的Orchestrator模塊會(huì)很有幫助。gulp.add方法其實(shí)就是Orchestrator.add方法(事實(shí)上所有的方法都是從Orchestrator繼承而來(lái)的)。但為什么你需要這個(gè)?
* 你不想“私有任務(wù)”(比如:不暴露給命令行工具)弄亂gulp任務(wù)列表。
* 你需要更多的動(dòng)態(tài)的和(或)可重用的子任務(wù)。
請(qǐng)注意,gulp(或grunt)并不總是當(dāng)前情境下的最佳工具。比如說(shuō),如果你需要拼接并使用uglify壓縮一系列的JavaScript文件,又或者你需要編譯一些SASS文件,你可能需要考慮使用makefile或npm run,通過(guò)命令行來(lái)實(shí)現(xiàn)。減少依賴(lài),減少配置,才是正解。
閱讀通過(guò)npm run來(lái)實(shí)現(xiàn)任務(wù)自動(dòng)化來(lái)了解更多信息。你需要明確通過(guò)一系列的“自定義構(gòu)建”后需要得到什么,而哪個(gè)工具最合適。
不過(guò),我覺(jué)得gulp是一個(gè)偉大的構(gòu)建系統(tǒng),我很喜歡使用它,它展現(xiàn)了Node.js中流的強(qiáng)大。
希望這些能夠幫到你!如果你有任何反饋或其他提議,請(qǐng)?jiān)谠u(píng)論中告訴我,或者加我的twitter:@webprolific
小廣告:更多內(nèi)容歡迎來(lái)我的博客,共同探討
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87638.html
摘要:為何選擇引擎微信小游戲推出之后,很多公司也相應(yīng)的進(jìn)入到微信小游戲這個(gè)領(lǐng)域,現(xiàn)在市場(chǎng)上的游戲開(kāi)發(fā)引擎,如都對(duì)小游戲有了很好的兼容性。 1. 為何選擇Laya引擎 微信小游戲推出之后,很多公司也相應(yīng)的進(jìn)入到微信小游戲這個(gè)領(lǐng)域,現(xiàn)在市場(chǎng)上的游戲開(kāi)發(fā)引擎,如Cocos、Egret、Laya都對(duì)小游戲有了很好的兼容性。目前公司技術(shù)棧主要是使用Cocos和Laya,經(jīng)過(guò)幾個(gè)項(xiàng)目的接觸,考量了引擎在...
摘要:前言月份開(kāi)始出沒(méi)社區(qū),現(xiàn)在差不多月了,按照工作的說(shuō)法,就是差不多過(guò)了三個(gè)月的試用期,準(zhǔn)備轉(zhuǎn)正了一般來(lái)說(shuō),差不多到了轉(zhuǎn)正的時(shí)候,會(huì)進(jìn)行總結(jié)或者分享會(huì)議那么今天我就把看過(guò)的一些學(xué)習(xí)資源主要是博客,博文推薦分享給大家。 1.前言 6月份開(kāi)始出沒(méi)社區(qū),現(xiàn)在差不多9月了,按照工作的說(shuō)法,就是差不多過(guò)了三個(gè)月的試用期,準(zhǔn)備轉(zhuǎn)正了!一般來(lái)說(shuō),差不多到了轉(zhuǎn)正的時(shí)候,會(huì)進(jìn)行總結(jié)或者分享會(huì)議!那么今天我就...
摘要:主有前端后端,并加,各一名。本著工欲善其事,必先利其器的理念,一直以來(lái)在工作效率這塊,略懷執(zhí)念一個(gè)問(wèn)題不應(yīng)該被解決兩次。下圖為開(kāi)發(fā)項(xiàng)目機(jī)制所涉及到的插件工欲善其事,必先利其器,語(yǔ)言,框架皆可以歸結(jié)為器而不當(dāng)僅局限于開(kāi)發(fā)工具以及機(jī)。 原文鏈接: http://www.jeffjade.com/2016/05/08/106-vue-es6-jade-scss-webpack-gulp/ 一...
摘要:當(dāng)接收一個(gè)回調(diào)函數(shù)的時(shí)候,一定要注意回調(diào)函數(shù)中的參數(shù)。主要作用就是用來(lái)讀取文件或者文件夾中的數(shù)據(jù)。表示文件的名稱(chēng)指的是發(fā)生的變化使用技巧的進(jìn)一步使用,可以參照中文官網(wǎng)中的技巧集。 Gulp 簡(jiǎn)介 Gulp 對(duì)現(xiàn)在的前端而言,是一個(gè)稍微老舊的工具了,但是,為了復(fù)習(xí)以前學(xué)過(guò)的內(nèi)容,還是把它翻出來(lái),放在自己的博客中。說(shuō)不定哪天又用到了呢。 需要說(shuō)明的是,這里使用的 Gulp 版本是 3.9....
閱讀 1361·2021-09-24 10:26
閱讀 3678·2021-09-06 15:02
閱讀 632·2019-08-30 14:18
閱讀 588·2019-08-30 12:44
閱讀 3128·2019-08-30 10:48
閱讀 1952·2019-08-29 13:09
閱讀 2006·2019-08-29 11:30
閱讀 2292·2019-08-26 13:36