摘要:跟現(xiàn)在的類似的,把命令行工具從的核心代碼中剝離了。和都能使用獨(dú)立出來的命令行工具。是無法做出相應(yīng)的區(qū)分的。之前的中,在我們傳入一個(gè)通配符和可選參數(shù)后,我們可以再指定一個(gè)任務(wù)數(shù)組或者一個(gè)回調(diào)函數(shù)用來處理事件數(shù)據(jù)。
原文鏈接:The Complete-Ish Guide to Upgrading to Gulp 4
雖然Gulp4始終在開發(fā)中,但是你要堅(jiān)信在將來的某一天你一定可以等到它的正式版。嗯,某一天。所以現(xiàn)在我想先向你們介紹Gulp3.x和Gulp4之間的不同,同時(shí)希望能夠幫助你將來能相對(duì)無痛的遷移到新的版本。
安裝在你開始使用最新版的Gulp之前,你必須要先檢查一下你Gulp的版本。通常,你只需要更新你的package.json中的版本號(hào)就行了,不過有時(shí)候你也有可能碰到一些額外的麻煩。最可能的原因是你分別在項(xiàng)目文件夾下和全局環(huán)境中都安裝了Gulp(如果你讀過了這篇文章the practice of using npm scripts to access the locally installed version of CLI’s,那就好辦多了。雖然在這里它可能還是幫不了你太多)。因此,首先你要把你項(xiàng)目文件夾下的Gulp刪除,如果你在全局環(huán)境中也安裝了Gulp,最好也把它刪了。
npm uninstall gulp --save-dev npm uninstall gulp -g
現(xiàn)在你就可以在你的項(xiàng)目中安裝Gulp4。由于它還沒有正式發(fā)布,我們只能直接通過Github來安裝它:
npm install gulpjs/gulp.git#4.0 --save-dev
當(dāng)它提交到npm庫之后,你就可以像平常一樣使用npm install gulp --save-dev了。并且當(dāng)它發(fā)布正式版本后,我們也最好不要從Github上安裝,改為直接從npm上進(jìn)行安裝。好了,現(xiàn)在我們還有另一個(gè)東西需要安裝:命令行工具。跟現(xiàn)在的Grunt類似的,Gulp4把命令行工具從Gulp的核心代碼中剝離了。Gulp3和Gulp4都能使用獨(dú)立出來的命令行工具。
npm install gulp-cli --save-dev
如果你不想在你的項(xiàng)目中使用npm scripts,你需要使用-g替換-save-dev來進(jìn)行全局安裝。現(xiàn)在你就可以像以前一樣使用gulp命令了,但是你應(yīng)該會(huì)得到一個(gè)錯(cuò)誤信息,因?yàn)槟阈枰履愕?b>gulpfile.js來兼容最新版的Gulp。
任務(wù)重構(gòu)如果你原來的任務(wù)代碼結(jié)構(gòu)十分簡(jiǎn)單,任務(wù)之前沒有相互的依賴。那很走運(yùn),你將不需要做任何修改!不過令人哀傷的是,大部分人都不得不做一些調(diào)整。Gulp4最大的一個(gè)改變就是gulp.task函數(shù)現(xiàn)在只支持兩個(gè)參數(shù),分別是任務(wù)名和運(yùn)行任務(wù)的函數(shù)。舉個(gè)例子,下面的任務(wù)代碼可以很好的運(yùn)行在Gulp3和Gulp4上面:
gulp.task("clean", function() {...})
但是當(dāng)你使用三個(gè)參數(shù)時(shí)該怎么辦?我們要如何指定任務(wù)之間的依賴關(guān)系?這時(shí)新的gulp.series和gulp.parallel函數(shù)應(yīng)該能幫助你解決難題。這兩個(gè)函數(shù)都可以接受數(shù)個(gè)函數(shù)或任務(wù)名作為參數(shù),經(jīng)過組合后,返回一個(gè)新的函數(shù)。gulp.series會(huì)返回一個(gè)函數(shù)用來順序執(zhí)行它所接受的任務(wù)/函數(shù),而gulp.parallel返回的函數(shù)則會(huì)并行的運(yùn)行它們。Gulp總算能夠讓我們自由的選擇以串行或并行的方式來執(zhí)行任務(wù)而不再需要其他的第三方依賴(比如常用的run-sequence),也不用再定義一堆讓人看不懂的任務(wù)依賴。
如果你以前是這么寫:
gulp.task("styles", ["clean"], function() { ... });
那你現(xiàn)在可以這樣:
gulp.task("styles", gulp.series("clean", function() { ... }));
在改寫的時(shí)候,不要忘了其實(shí)現(xiàn)在你處理主要任務(wù)的函數(shù)也是放在gulp.series里面調(diào)用,所以不要忘了在結(jié)尾加上括號(hào)。很多人經(jīng)常犯這個(gè)錯(cuò)誤。
注意,由于gulp.series和gulp.parallel返回的是一個(gè)函數(shù),所以他們是可以被嵌套調(diào)用的。如果您的任務(wù)往往有多個(gè)依賴任務(wù),你會(huì)經(jīng)常嵌套調(diào)用它們。比如這個(gè)例子:
gulp.task("default", ["scripts", "styles"], function() { ... });
你可以改寫成:
gulp.task("default", gulp.series(gulp.parallel("scripts", "styles"), function() { ... }));
看過去,這樣代碼讀起來非常吃力。不過考慮到這樣會(huì)使你任務(wù)流程控制更加的靈活,這點(diǎn)犧牲也就無所謂了。當(dāng)然我覺得你也可以自己封裝一些helper/alias函數(shù)來優(yōu)化的你的代碼,提高可讀性,但我應(yīng)該不會(huì)這么去做。
依賴陷阱在Gulp3中,假設(shè)你設(shè)定幾個(gè)有相同依賴的任務(wù),然后運(yùn)行它們,Gulp會(huì)檢測(cè)出這些將要運(yùn)行的任務(wù)的依賴是一樣的,然后只會(huì)運(yùn)行一次依賴任務(wù)。然而現(xiàn)在我們不再顯式的指定任務(wù)之間的依賴,而是通過series和parallel函數(shù)來組合任務(wù),這樣會(huì)導(dǎo)致那些本應(yīng)該只運(yùn)行一次的任務(wù),變成多次運(yùn)行。Gulp4是無法做出相應(yīng)的區(qū)分的。所以我們要改變我們指定任務(wù)依賴的思路。
讓我們看一下這個(gè)Gulp3的例子:
// default任務(wù),需要依賴scripts和styles gulp.task("default", ["scripts", "styles"], function() {...}); // script折styles任務(wù)都依賴clean gulp.task("styles", ["clean"], function() {...}); gulp.task("scripts", ["clean"], function() {...}); // clean任務(wù)用來清空目錄 gulp.task("clean", function() {...});
我們注意到styles和scripts任務(wù)都依賴clean任務(wù)。當(dāng)你運(yùn)行default任務(wù)時(shí),Gulp3會(huì)率先運(yùn)行styles和scripts任務(wù),又因?yàn)闄z測(cè)到這兩個(gè)任務(wù)都有各自的依賴,所以需要優(yōu)先運(yùn)行它們的依賴任務(wù),這時(shí)Gulp注意到這兩個(gè)任務(wù)都依賴于clean,于是Gulp3將確保在回到styles和scripts任務(wù)之前,clean任務(wù)會(huì)被執(zhí)行且執(zhí)行一次。這很有用!但遺憾的是,我們?cè)谛掳姹局袑]辦法運(yùn)用這個(gè)特性。如果你在遷移到Gulp4的過程中只像下面的例子一樣做了簡(jiǎn)單的改變,clean任務(wù)將會(huì)被執(zhí)行兩次:
gulp.task("clean", function() {...}); gulp.task("styles", gulp.series("clean", function() {...})); gulp.task("scripts", gulp.series("clean", function() {...})); gulp.task("default", gulp.parallel("scripts", "styles"));
這是因?yàn)?b>parallel和series不是用來解決依賴的;他們只是用來把多個(gè)任務(wù)合并成一個(gè)。所以我們需要把共同依賴的任務(wù)抽離出來,然后用一個(gè)更大的串行任務(wù)來包裹它們,以此來模擬任務(wù)依賴關(guān)系:
友情提示:你最好不要在定義那些小任務(wù)之前就用它們來組合你的default任務(wù)。因?yàn)樵谀阏{(diào)用gulp.series("taskName")之前,你必須已經(jīng)定義好了一個(gè)名為"taskName"的任務(wù)。所以一般在Gulp4中,我們會(huì)在代碼的最后才定義default,而在Gulp3中你可以把它放在任何地方。
// 任務(wù)直接不再有依賴 gulp.task("styles", function() {...}); gulp.task("scripts", function() {...}); gulp.task("clean", function() {...}); // default任務(wù),需要依賴scripts和styles gulp.task("default", gulp.series("clean", gulp.parallel("scripts", "styles")));
如果照這么寫,當(dāng)你多帶帶運(yùn)行styles和scripts任務(wù)時(shí),clean任務(wù)就不會(huì)優(yōu)先自動(dòng)執(zhí)行。不過這問題也不大,在之前多帶帶運(yùn)行clean任務(wù)就可以了,一樣能把scripts和styles的文件夾清空。又或者你可以重新定義一下你的任務(wù),隨你,我也不確定怎樣會(huì)更好。
異步任務(wù)支持如果你執(zhí)行的是同步任務(wù),在Gulp3中不需要寫任何其他代碼,但是在Gulp4中就不能如此輕松了:現(xiàn)在也你必須運(yùn)行done回調(diào)(這可能是我最早發(fā)現(xiàn)的一個(gè)變化)。然后如果你執(zhí)行的是異步任務(wù),你則有三個(gè)選擇來確保Gulp能夠檢測(cè)到你的任務(wù)真的完成了,方法如下:
1) 回調(diào)你可以在你的任務(wù)函數(shù)的參數(shù)中提供一個(gè)回調(diào)函數(shù)并且在你的任務(wù)完成后調(diào)用它:
var del = require("del"); gulp.task("clean", function(done) { del([".build/"], done); });2) 流
你也可以返回一個(gè)流,通常通過gulp.src或vinyl-source-stream這個(gè)庫來創(chuàng)建。這一般也是最常用的方式:
gulp.task("somename", function() { return gulp.src("client/**/*.js") .pipe(minify()) .pipe(gulp.dest("build")); });3) Promise
Promise這個(gè)技術(shù)早已聲名鵲起而且在Node中已經(jīng)有了完整的實(shí)現(xiàn),所以這也會(huì)是一個(gè)很有用的方式。你只需要返回一個(gè)promise對(duì)象,Gulp就能知道任務(wù)在什么時(shí)候完成。
var promisedDel = require("promised-del"); gulp.task("clean", function() { return promisedDel([".build/"]); });其他的異步任務(wù)支持
感謝Gulp現(xiàn)在引入了async-done庫,在最新的版本中我們有更多的方式來確認(rèn)異步任務(wù)的完成。
4)子進(jìn)程你可以在你的任務(wù)中創(chuàng)建一些子進(jìn)程并返回!比如,你可以把你的npm scripts放到Gulp中執(zhí)行,這樣你就不需要為你的package.json中加載了百萬條命令而煩惱。你也可以通過這樣的封裝擺脫那些隨時(shí)可能過時(shí)的gulp插件。盡管這看上去像一個(gè)反模式,不過你還是有很多可以優(yōu)化它們的方法。
var spawn = require("child_process").spawn; gulp.task("clean", function() { return spawn("rm", ["-rf", path.join(__dirname, "build")]); });5)RxJS observable
我沒用過RxJS,它好像挺小眾的。不過對(duì)于那些RxJS的死忠粉絲,他們會(huì)很高興可以返回一個(gè)observable對(duì)象。
var Observable = require("rx").Observable; gulp.task("sometask", function() { return Observable.return(42); });監(jiān)聽
處理文件系統(tǒng)的監(jiān)聽和響應(yīng)的API也有了一點(diǎn)進(jìn)步。之前的API中,在我們傳入一個(gè)glob通配符和可選參數(shù)后,我們可以再指定一個(gè)任務(wù)數(shù)組或者一個(gè)回調(diào)函數(shù)用來處理事件數(shù)據(jù)。可是現(xiàn)在,任務(wù)隊(duì)列都是由serise或者parallel函數(shù)合并而成,這樣你就無法用一個(gè)回調(diào)來區(qū)分這些任務(wù),所以我們?nèi)∠诉@種簡(jiǎn)單監(jiān)聽回調(diào)的方式。取而代之的是,gulp.watch將像之前一樣會(huì)返回一個(gè)的“觀察”對(duì)象,不過你可以對(duì)它添加各種事件監(jiān)聽:
// 舊版 gulp.watch("js/**/*.js", function(event) { console.log("File " + event.path + " was " + event.type + ", running tasks..."); }); // 新版: var watcher = gulp.watch("js/**/*.js" /* 你可以在這里傳一些參數(shù)或者函數(shù) */); watcher.on("all", function(event, path, stats) { console.log("File " + path + " was " + event + ", running tasks..."); }); // 單個(gè)事件的監(jiān)聽 watcher.on("change", function(path, stats) { console.log("File " + path + " was changed, running tasks..."); }); watcher.on("add", function(path) { console.log("File " + path + " was added, running tasks..."); }); watcher.on("unlink", function(path) { console.log("File " + path + " was removed, running tasks..."); });
正如所看到的,在all和change的事件處理中,你還可以接受一個(gè)stats對(duì)象。stats對(duì)象只在他們可用的時(shí)候出現(xiàn)(我也不確定他們什么時(shí)候可用什么時(shí)候不可用),不過你可以設(shè)置alwaysStat選項(xiàng)的值為true來讓它始終出現(xiàn)。Gulp使用了chokidar庫來實(shí)現(xiàn)這些東西,閱讀chokidar的文檔能讓你了解的更多,盡管chokidar并不支持在事件回調(diào)中指定第三個(gè)參數(shù)。
使用函數(shù)由于現(xiàn)在每個(gè)任務(wù)基本上就是一個(gè)函數(shù),不需要任何依賴或其他的什么,實(shí)際上他們也僅僅是需要一個(gè)任務(wù)運(yùn)行器來確認(rèn)異步任務(wù)何時(shí)結(jié)束,我們可以把函數(shù)定義從gulp.task中獨(dú)立出來,而不僅僅作為一個(gè)簡(jiǎn)單回調(diào)函數(shù)傳給gulp.task。舉個(gè)例子,這個(gè)代碼之前我們?cè)凇耙蕾囅葳濉蹦莻€(gè)章節(jié)的結(jié)論:
gulp.task("styles", function() {...}); gulp.task("scripts", function() {...}); gulp.task("clean", function() {...}); gulp.task("default", gulp.series("clean", gulp.parallel("scripts", "styles")));
我把它變成:
// 只需要在`series` 和 `parallel` 中間引用函數(shù)名就能組成一個(gè)新任務(wù) gulp.task("default", gulp.series(clean, gulp.parallel(scripts, styles))); // 把單個(gè)任務(wù)變成一個(gè)函數(shù) function styles() {...} function scripts() {...} function clean() {...}
這里有幾點(diǎn)要注意的地方:
1.由于js是有函數(shù)定義提升的,函數(shù)的定義可以放在你定義default任務(wù)之后,不像之前說的,如果你要用一些小任務(wù)組成一個(gè)新任務(wù)的時(shí)候,你就必須要先定義那些小任務(wù)。這樣就使得你可以在一開始就定義好實(shí)際要運(yùn)行的任務(wù),這樣別人閱讀起來也更方便一些,以免別人還要在翻閱了一堆其他任務(wù)代碼后,才能發(fā)現(xiàn)藏在最后的實(shí)際要運(yùn)行的那些。
2.styles, scripts, 和 clean 現(xiàn)在都相當(dāng)于“私有”任務(wù),他們無法通過gulp命令行來運(yùn)行。
3.這樣就沒有那么多匿名函數(shù)了。
4.也沒有那么多被引號(hào)包裹住的“任務(wù)”名了,這樣意味著你可以通過你的代碼編輯器/IDE幫你檢查拼寫錯(cuò)誤,而不用在運(yùn)行Gulp的時(shí)候才能發(fā)現(xiàn)錯(cuò)誤。
5.即使把“任務(wù)”函數(shù)放在多個(gè)文件中定義,也能方便的把它們引用到同一個(gè)文件中,然后再通過gulp.task把它們變成實(shí)際可用的任務(wù)。
6.這些任務(wù)都是可以獨(dú)立測(cè)試的(如果你要測(cè)試)而不需要gulp。
當(dāng)然第2點(diǎn)也是可以修改的,如果你希望它們是可以被gulp命令行所執(zhí)行的:
gulp.task(styles);
這樣你就能新建了一個(gè)可以運(yùn)行在命令行的“styles”任務(wù)。注意你可從來沒有在代碼中定義過它的名字。gulp.task可以很智能的把函數(shù)名轉(zhuǎn)成任務(wù)名。當(dāng)然,匿名函數(shù)是不行的:Gulp會(huì)拋出一個(gè)錯(cuò)誤當(dāng)你想要把匿名函數(shù)指定成一個(gè)任務(wù),卻沒有給它起一個(gè)新名字。
如果你想給函數(shù)起個(gè)別名,你可以在函數(shù)的displayName屬性中指定它:
function styles(){...} styles.displayName = "pseudoStyles"; gulp.task(styles);
現(xiàn)在任務(wù)名將會(huì)從“styles”變成“pseudoStyles”。你也可以通過指定description屬性來給你的任務(wù)添加描述。你可以通過gulp --tasks命令來查看這些描述:
function styles(){...} styles.displayName = "pseudoStyles"; styles.description = "Does something with the stylesheets." gulp.task(styles);
$ gulp --tasks [12:00:00] Tasks for ~/project/gulpfile.js [12:00:00] └── pseudoStyles Does something with the stylesheets.
你甚至可以給你其他已經(jīng)注冊(cè)的任務(wù)添加描述,比如default。首先你要運(yùn)行gulp.task("taskName")來取人這個(gè)任務(wù)已經(jīng)被定義過了,然后才給它添加描述:
gulp.task("default", gulp.series(clean, gulp.parallel(scripts, styles))); // Use gulp.task to retrieve the task var defaultTask = gulp.task("default"); // give it a description defaultTask.description = "Does Default Stuff";
我們也可以簡(jiǎn)化它,取消中間值:
gulp.task("default", gulp.series(clean, gulp.parallel(scripts, styles))); gulp.task("default").description = "Does Default Stuff";
對(duì)那些不熟悉你的項(xiàng)目的人來說,這些描述是相當(dāng)有用的。所以我建議在任何情況下都要添加它:有時(shí)它比注釋還更有用。最后總結(jié)一下,這是我推薦的Gulp4的最佳實(shí)踐:
gulp.task("default", gulp.series(clean, gulp.parallel(scripts, styles))); gulp.task("default").description = "This is the default task and it does certain things"; function styles() {...} function scripts() {...} function clean() {...}
如果你運(yùn)行gulp --tasks,你將會(huì)看到:
$ gulp --tasks [12:00:00] Tasks for ~localhostgulp4testgulpfile.js [12:00:00] └─┬ default This is the default task and it does certain things [12:00:00] └─┬[12:00:00] ├── clean [12:00:00] └─┬ [12:00:00] ├── scripts [12:00:00] └── styles
你會(huì)發(fā)現(xiàn)這里不僅有你添加的描述,你還能看到完整的運(yùn)行隊(duì)列樹。我也很樂意聽到你對(duì)最佳實(shí)踐有其他看法,不過在闡述結(jié)論前最好先跟你的團(tuán)隊(duì)討論一下。
不管怎么樣,我還是很高興看到Gulp4有很多有用的改進(jìn),但是它們也給遷移帶來了不少痛苦。我希望這份指南能幫助你順利遷移到Gulp4當(dāng)它正式發(fā)布后(可能過幾天……也可能……)。上帝保佑~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79570.html
摘要:前言周日在公司的新電腦在以前配置的目錄按下時(shí)發(fā)現(xiàn)報(bào)了錯(cuò),百度了一下得知原來已經(jīng)到了版本,就花了一點(diǎn)時(shí)間去升了個(gè)級(jí),順便記下我個(gè)人使用到的配置文件新版本的不同點(diǎn),文筆和水平有限,多多見諒新引入新引入的可替換老版的和,代碼更簡(jiǎn)潔是任務(wù)監(jiān)聽是任務(wù) 前言 周日在公司的新電腦在以前gulp3.9配置的目錄按下npm install時(shí)發(fā)現(xiàn)報(bào)了錯(cuò),百度了一下得知原來gulp已經(jīng)到了4.0版本,就花了...
摘要:通過輸入文件流,將文件寫入硬盤,并輸出所有數(shù)據(jù),能繼續(xù)向下游,所以文件流可以繼續(xù)被處理并被寫入到其他地方。如果寫入文件夾不存在,就會(huì)創(chuàng)建它。第二個(gè)參數(shù),當(dāng)前任務(wù)依賴的任務(wù)列表,依賴任務(wù)在當(dāng)前任務(wù)運(yùn)行之前完成。 gulp 簡(jiǎn)介 用自動(dòng)化構(gòu)建工具增強(qiáng)你的工作流程。 通過代碼優(yōu)于配置的策略,Gulp 讓簡(jiǎn)單的任務(wù)簡(jiǎn)單,復(fù)雜的任務(wù)可管理。 利用 Node.js 流的威力,你可以快速構(gòu)建項(xiàng)目并...
摘要:介紹這段配置是之前的版本不適配新版本后,更新到了的新寫法。在業(yè)務(wù)中,目前使用這份配置的是一個(gè)項(xiàng)目,所以增加了來啟動(dòng)。 介紹 這段配置是之前的gulp版本不適配新版本node后,更新到了gulp4的新寫法。 在業(yè)務(wù)中,目前使用這份配置的是一個(gè)Koa2+njk項(xiàng)目,所以增加了nodemon來啟動(dòng)server。 分別用到的技術(shù)為: Less + autoprefixer + cleancs...
摘要:層疊樣式表二修訂版這是對(duì)作出的官方說明。速查表兩份表來自一份關(guān)于基礎(chǔ)特性,一份關(guān)于布局。核心第一篇一份來自的基礎(chǔ)參考指南簡(jiǎn)寫速查表簡(jiǎn)寫形式參考書使用層疊樣式表基礎(chǔ)指南,包含使用的好處介紹個(gè)方法快速寫成高質(zhì)量的寫出高效的一些提示。 迄今為止,我已經(jīng)收集了100多個(gè)精通CSS的資源,它們能讓你更好地掌握CSS技巧,使你的布局設(shè)計(jì)脫穎而出。 CSS3 資源 20個(gè)學(xué)習(xí)CSS3的有用資源 C...
摘要:本文轉(zhuǎn)載自眾成翻譯譯者文藺鏈接原文譯者注本文講到的可能和我們通常理解的略有差異。文中部分主要講到的是,這一點(diǎn)可能在一些開發(fā)者看來是有爭(zhēng)議的。談到,最好也是最簡(jiǎn)單的辦法是使用免費(fèi)開源的框架。需要快速開發(fā)打樣那可能最好的選擇。 本文轉(zhuǎn)載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/861原文:http://www.telerik.com/blogs/h...
閱讀 1310·2021-11-22 14:44
閱讀 2445·2021-09-30 09:47
閱讀 1221·2021-09-09 11:56
閱讀 2077·2021-09-08 09:45
閱讀 3953·2021-08-31 09:40
閱讀 1250·2019-08-30 15:52
閱讀 2044·2019-08-30 14:09
閱讀 1578·2019-08-26 17:04