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