版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
JavaScriptWeb應(yīng)用開發(fā)(上篇)目錄\h第一部分構(gòu)建過程\h第1章構(gòu)建優(yōu)先\h1.1問題出現(xiàn)了\h1.1.145分鐘內(nèi)每秒損失17萬美元\h1.1.2構(gòu)建優(yōu)先\h1.1.3繁瑣的前戲\h1.2遵守構(gòu)建優(yōu)先原則,提前計劃\h構(gòu)建優(yōu)先原則的核心法則\h1.3構(gòu)建過程\h1.4處理應(yīng)用的復雜度和設(shè)計理念\h1.5鉆研構(gòu)建優(yōu)先原則\h1.5.1檢查代碼質(zhì)量\h1.5.2在命令行中使用lint工具\h1.6總結(jié)\h第2章編寫構(gòu)建任務(wù),制定流程\h2.1介紹Grunt\h2.1.1安裝Grunt\h2.1.2設(shè)置第一個Grunt任務(wù)\h2.1.3使用Grunt管理構(gòu)建過程\h2.2預處理和靜態(tài)資源優(yōu)化\h2.2.1詳述預處理\h2.2.2處理LESS\h2.2.3打包靜態(tài)資源\h2.2.4簡化靜態(tài)資源\h2.2.5創(chuàng)建子圖集\h2.3檢查代碼完整性\h2.3.1清理工作目錄\h2.3.2使用lint程序檢查代碼\h2.3.3自動運行單元測試\h2.4首次自己編寫構(gòu)建任務(wù)\h2.5案例分析:數(shù)據(jù)庫任務(wù)\h2.6總結(jié)\h第3章精通環(huán)境配置和開發(fā)流程\h3.1應(yīng)用的環(huán)境\h3.1.1配置構(gòu)建模式\h3.1.2環(huán)境層面的配置\h3.1.3開發(fā)環(huán)境有什么特別之處\h3.2配置環(huán)境\h3.2.1瀑布式存儲配置的方法\h3.2.2通過加密增強環(huán)境配置的安全性\h3.2.3使用系統(tǒng)級方式設(shè)置環(huán)境層面的配置\h3.2.4在代碼中使用瀑布式方法合并配置\h3.3自動執(zhí)行繁瑣的首次設(shè)置任務(wù)\h3.4在持續(xù)開發(fā)環(huán)境中工作\h3.4.1監(jiān)視變動,爭分奪秒\h3.4.2監(jiān)視Node應(yīng)用的變動\h3.4.3選擇一款合適的文本編輯器\h3.4.4手動刷新瀏覽器已經(jīng)過時了\h3.5總結(jié)\h第4章發(fā)布、部署和監(jiān)控\h4.1發(fā)布應(yīng)用\h4.1.1優(yōu)化圖像\h4.1.2緩存靜態(tài)資源\h4.1.3內(nèi)嵌對首屏至關(guān)重要的CSS\h4.1.4部署前要測試\h4.2預部署操作\h4.2.1語義化版本\h4.2.2使用更改日志\h4.2.3提升版本號時提交更改日志\h4.3部署到Heroku\h4.3.1在Heroku的服務(wù)器中構(gòu)建\h4.3.2管理多個環(huán)境\h4.4持續(xù)集成\h4.4.1使用Travis托管的CI\h4.4.2持續(xù)部署\h4.5監(jiān)控和診斷\h4.5.1日志和通知\h4.5.2調(diào)試Node應(yīng)用\h4.5.3分析性能\h4.5.4運行時間和進程管理\h4.6總結(jié)\h第二部分管理復雜度\h第5章理解模塊化和依賴管理\h5.1封裝代碼\h5.1.1理解單一職責原則\h5.1.2信息隱藏和接口\h5.1.3作用域和this關(guān)鍵字\h5.1.4嚴格模式\h5.1.5提升變量的作用域\h5.2JavaScript模塊\h5.2.1閉包和模塊模式\h5.2.2原型的模塊化\h5.2.3CommonJS模塊\h5.3管理依賴\h5.3.1依賴圖\h5.3.2介紹RequireJS\h5.3.3Browserify:在瀏覽器中使用CJS模塊\h5.3.4Angular管理依賴的方式\h5.4理解包管理\h5.4.1Bower簡介\h5.4.2大型庫,小組件\h5.4.3選擇合適的模塊系統(tǒng)\h5.4.4學習循環(huán)依賴\h5.5ECMAScript6新功能簡介\h5.5.1在Grunt任務(wù)中使用Traceur\h5.5.2Harmony中的模塊\h5.5.3創(chuàng)建塊級作用域的let關(guān)鍵字\h5.6總結(jié)\h第6章理解JavaScript中的異步流程控制方法\h6.1使用回調(diào)\h6.1.1跳出回調(diào)之坑\h6.1.2解開混亂的回調(diào)\h6.1.3嵌套請求\h6.1.4處理異步流程中的錯誤\h6.2使用async庫\h6.2.1使用瀑布式、串行還是并行\(zhòng)h6.2.2異步函數(shù)式任務(wù)\h6.2.3異步任務(wù)隊列\(zhòng)h6.2.4制定流程和動態(tài)流程\h6.3使用Promise對象\h6.3.1Promise對象基礎(chǔ)知識\h6.3.2鏈接Promise對象\h6.3.3控制流程\h6.3.4處理被拒絕的Promise對象\h6.4理解事件\h6.4.1事件和DOM\h6.4.2自己實現(xiàn)事件發(fā)射器\h6.5展望:ES6生成器\h6.5.1創(chuàng)建第一個生成器\h6.5.2生成器的異步性\h6.6總結(jié)
第一部分構(gòu)建過程本書第一部分專門介紹構(gòu)建過程,還會通過實例介紹Grunt。這一部分既有理論也有實踐,目的是告訴你什么是構(gòu)建過程,為什么以及如何使用構(gòu)建過程。第1章說明構(gòu)建優(yōu)先原則包含的兩層意思:構(gòu)建過程和應(yīng)用復雜度管理。然后開始編寫第一個構(gòu)建任務(wù):使用lint程序檢查代碼,避免有句法錯誤。第2章專門介紹構(gòu)建任務(wù)。你會了解組成一次構(gòu)建的各項任務(wù),如何配置任務(wù),以及如何自己編寫任務(wù)。針對每種情況,我們都會先講理論,然后再使用Grunt編寫實例。第3章介紹如何配置應(yīng)用的環(huán)境,而且要安全存儲敏感信息。我們會說明搭建開發(fā)環(huán)境的流程,以及如何自動完成這些構(gòu)建步驟。第4章再介紹一些需要在發(fā)布應(yīng)用時執(zhí)行的任務(wù),例如優(yōu)化靜態(tài)資源和管理文檔。你會學到如何使用持續(xù)集成服務(wù)檢查代碼的質(zhì)量。我們還會把應(yīng)用部署到線上環(huán)境,讓你實際體驗一把。
第1章構(gòu)建優(yōu)先本章內(nèi)容現(xiàn)代應(yīng)用設(shè)計面臨的問題什么是構(gòu)建優(yōu)先原則構(gòu)建過程管理應(yīng)用中的復雜度使用正確的方式開發(fā)應(yīng)用可能很難,我們要合理規(guī)劃。我曾只用一個周末就開發(fā)出了應(yīng)用,但應(yīng)用設(shè)計得可能并不好。創(chuàng)建隨時會扔掉的原型可以即興發(fā)揮,但是開發(fā)一個可維護的應(yīng)用則需要規(guī)劃,要知道怎么把腦海中設(shè)想的功能組織在一起,甚至還要考慮到不久之后可能會添加的功能。我曾付出無數(shù)努力,但應(yīng)用的前端還是差強人意。后來我發(fā)現(xiàn),后端服務(wù)通常都有專門的架構(gòu),專門用于規(guī)劃、設(shè)計和概覽這些服務(wù),而且往往還不止一個架構(gòu),而是一整套??墒乔岸碎_發(fā)的情況卻完全不同,前端開發(fā)者會先開發(fā)出一個可以運行的應(yīng)用原型,然后運行這個原型,希望在生產(chǎn)環(huán)境中依然正常。前端開發(fā)同樣需要規(guī)劃架構(gòu),像后端開發(fā)一樣去設(shè)計應(yīng)用。以前,我們會從網(wǎng)上復制一些代碼片段,然后粘貼到頁面中,就這樣收工了??墒沁@樣的日子早已過去,先把JavaScript代碼攪和在一起,事后再做修改,不符合現(xiàn)代標準了。如今,JavaScript是開發(fā)的焦點,有很多框架和庫可以選擇,這些框架和庫能幫助我們組織代碼,我們不會再編寫一整個龐大的應(yīng)用了,更多的是編寫小型組件??删S護性不是隨意就能實現(xiàn)的,我們從開發(fā)應(yīng)用伊始就要考慮可維護性,并在這個原則的指導下設(shè)計應(yīng)用。設(shè)計應(yīng)用時如果不考慮可維護性,隨著功能的不斷增加,應(yīng)用就會像疊疊樂搭出的積木塔一樣慢慢傾斜。如果不考慮可維護性,最后根本無法再往這個塔上放任何積木。應(yīng)用的代碼會變得錯綜復雜,缺陷越來越難追查。重構(gòu)就要中斷產(chǎn)品開發(fā),業(yè)務(wù)可經(jīng)不起這樣折騰。而且還要保持原有的發(fā)布周期,根本不能讓積木塔倒下,所以我們只能妥協(xié)。1.1問題出現(xiàn)了你可能想把一個新功能部署到生產(chǎn)環(huán)境,而且想自己動手部署。你要用多少步完成這次部署?八步還是五步?為什么你要在部署這樣的日常工作中冒險呢?部署應(yīng)該和在本地開發(fā)應(yīng)用一樣,只需一步就行??上聦嵅⒎侨绱?。我以前會手動執(zhí)行部署過程中的很多步驟,你是不是也是這樣?當然,你一步就能編譯好應(yīng)用,或者可能會使用服務(wù)器端解釋型語言,根本不用事先編譯。如果以后需要把數(shù)據(jù)庫更新到最新版本,你甚至可能會編寫一個腳本執(zhí)行升級操作,但還是要登入數(shù)據(jù)庫服務(wù)器,上傳這個腳本文件,然后自己動手更新數(shù)據(jù)庫模式。做得不錯,數(shù)據(jù)庫已經(jīng)更新了,可是有地方出錯了,應(yīng)用拋出了錯誤。你看了下時間,應(yīng)用已經(jīng)下線超過10分鐘了。這只是一次簡單的升級啊,怎么會出錯呢?你查看日志,發(fā)現(xiàn)原來是忘記把新變量添加到配置文件里了,真是太傻了。你立即加上了新變量,抱怨著這次與代碼基的斗爭。你忘記在部署前修改配置文件,在部署到生產(chǎn)環(huán)境前忘了更新配置。這種情況是不是聽起來很熟悉?不要害怕,這種情況很常見,在很多應(yīng)用中都存在。我們來看看下面這個危險的案例。1.1.145分鐘內(nèi)每秒損失17萬美元我敢肯定,一個嚴重問題導致?lián)p失幾乎五億美元的案例會讓你打起精神。在騎士資本公司就發(fā)生過這樣的事。1他們開發(fā)了一個新功能,讓股票交易員參與一個叫“零售流動性計劃”(RetailLiquidityProgram,簡稱RLP)的項目中。RLP的目的是取代已經(jīng)停用九年的“權(quán)力限定”(PowerPeg,簡稱PP)功能。RLP的代碼中重用了一個用來激活PP功能的標志,添加RLP時,他們把PP移除了,所以一切都正常運行著,至少他們認為是正常的。但是,當他們打開這個標志時,問題出現(xiàn)了。1關(guān)于騎士資本公司這次事件的詳情,請訪問\hhttp://bevacqua.io/bf/knight。他們在部署時沒有采用正式的過程,而且只由一個技術(shù)人員手動執(zhí)行。這個人忘記把代碼改動部署到八個服務(wù)器中的某一個,因此,在這個服務(wù)器中,這個標志控制的是PP功能,而不是RLP功能。直到一星期后他們打開這個標志時才發(fā)現(xiàn)問題:他們在七個服務(wù)器中激活了RLP,卻在最后一個服務(wù)器上激活了停用九年的PP功能。這臺服務(wù)器上處理的訂單觸發(fā)執(zhí)行的是PP代碼,而不是RLP。這樣一來,發(fā)送到交易中心的訂單類型是錯誤的。他們試圖補救,但情況進一步惡化了,因為他們從已經(jīng)部署了RLP的服務(wù)器中把RLP刪除了。長話短說,他們在不到一小時的時間內(nèi)損失了差不多4億6千萬美元。他們只要使用更正式的構(gòu)建過程,就能避免公司的衰敗。想到這一點,就會發(fā)現(xiàn)這整件事都是那么不可思議,不負責任,其實又應(yīng)該是很容易避免的。當然,這是個極端案例,但明確表明了我的觀點:自動化的過程能盡量避免人為錯誤,至少也能更早發(fā)現(xiàn)問題。1.1.2構(gòu)建優(yōu)先我寫這本書的目的是教你使用構(gòu)建優(yōu)先原則,在還未編寫任何代碼之前就做好設(shè)計,讓應(yīng)用的結(jié)構(gòu)清晰,易于測試。你會學習過程自動化的知識,減少人為出錯的可能性,避免重蹈騎士資本的覆轍。構(gòu)建優(yōu)先原則是設(shè)計結(jié)構(gòu)清晰、易于測試的應(yīng)用之基礎(chǔ),使用這一原則開發(fā)出來的應(yīng)用易于維護,也易于重構(gòu)。構(gòu)建優(yōu)先原則的兩個基本要素是過程自動化和合理的設(shè)計。為了教你使用構(gòu)建優(yōu)先原則,本書會向你展示能改進軟件質(zhì)量和Web開發(fā)流程的技術(shù)。在第一部分,首先要學習如何建立適用于現(xiàn)代Web應(yīng)用開發(fā)的構(gòu)建過程,然后示范能提高日常開發(fā)效率的最佳實踐,例如修改代碼后執(zhí)行的任務(wù)、在終端里只輸入一個命令就部署應(yīng)用的方式,以及如何監(jiān)控生產(chǎn)環(huán)境中的應(yīng)用狀態(tài)。本書第二部分講管理復雜度和設(shè)計,專注于應(yīng)用的質(zhì)量。在這一部分,我會比較當前可用的一些模塊化方案,介紹如何更好地編寫模塊化的JavaScript組件。JavaScript中的異步流越來越復雜,越來越長,因此我單獨準備了一章,讓你深入了解如何編寫簡潔的異步代碼,此外還會學習用來提升異步代碼質(zhì)量的不同工具。Backbone是入門首選的客戶端MVC框架,我會介紹一些足夠你開始使用JavaScript開發(fā)MVC應(yīng)用所需的知識。前面我提到過,易于測試對應(yīng)用來說很重要,雖然我們已經(jīng)實現(xiàn)了模塊化,向正確的方向邁出了一大步,但還是要在單獨的一章中說明測試。最后一章剖析一個流行的API設(shè)計思想,即REST(RepresentationalStateTransfer的縮寫,即“表現(xiàn)層狀態(tài)轉(zhuǎn)換”),我會幫助你設(shè)計自己的API,還會深入說明服務(wù)器端的應(yīng)用架構(gòu),不過仍然會密切關(guān)注前端。在探索構(gòu)建過程之前,我們再來看一個危險的案例。這個案例遇到的問題,只要遵循構(gòu)建優(yōu)先原則,通過實現(xiàn)過程自動化就能避免。1.1.3繁瑣的前戲如果新成員加入團隊后的設(shè)置步驟太復雜,也表明自動化程度不高。我以前參與的一些項目,首次搭建開發(fā)環(huán)境要一周時間,真是痛苦。在你想弄明白代碼的作用之前,竟然要浪費一周時間。我要下載大約60GB的數(shù)據(jù)庫備份,還要創(chuàng)建一個數(shù)據(jù)庫,配置一些以前從未聽說過的選項,例如排序規(guī)則,然后還得運行一系列腳本,升級模式,可這些腳本甚至不能完全正常運行。解決這個問題之后,還要在自己的環(huán)境中安裝指定的過時已久的Windows媒體播放器的解碼器,那感覺就像把一頭豬塞進放滿東西的冰箱一樣,純屬徒勞。最后,我沖了一杯咖啡,試圖一次編譯好130多個大型項目。可是,忘了安裝外部依賴,我想,安裝依賴就行了吧,但不行,還要編譯C++程序,這樣解碼器才能重新運行。我再次編譯,又過了20分鐘。還不行!真煩。或許我可以問問身邊的人,可是沒人確切知道該怎么做。他們一開始都經(jīng)歷過這樣痛苦的過程,但都不記得具體應(yīng)該怎么做了。查查維基百科?當然可以,但信息記得零零散散,并不能用來解決遇到的具體問題。公司從未制定正式的初始化流程,事情變得越來越復雜,也就很難再去制定一個流程。他們不得不處理巨量的備份、升級腳本、解碼器和網(wǎng)站所需的多個服務(wù),哪怕是改動一個分號也要花一小時編譯項目。如果他們從一開始就自動執(zhí)行這些步驟,遵循構(gòu)建優(yōu)先原則,這個過程會順利得多。騎士資本的潰敗和這個過度復雜的設(shè)置故事有一個共同點:如果他們能提前做好計劃,自動執(zhí)行構(gòu)建和部署,就能避免問題。提前計劃,自動執(zhí)行應(yīng)用相關(guān)的操作,這是構(gòu)建優(yōu)先原則的兩個基本要素,下一節(jié)會詳細說明。1.2遵守構(gòu)建優(yōu)先原則,提前計劃在騎士資本的案例中,他們忘了把代碼部署到其中一個服務(wù)器,即使有一步部署方案能自動把代碼部署到所有服務(wù)器,也無法避免這個公司破產(chǎn)。這個案例深層次的問題是代碼質(zhì)量,因為他們的代碼基中存在已經(jīng)差不多十年不用的代碼。不增加功能的徹底重構(gòu)對產(chǎn)品經(jīng)理沒有吸引力,他們的目標是提升面向客戶的可視化產(chǎn)品,而不是底層的軟件。不過,你可以逐漸改進代碼基,重構(gòu)你接觸到的代碼,為重構(gòu)后的功能編寫測試,把過時的代碼包裝到接口中,以后再重構(gòu)——這樣做能不斷提升項目中代碼的平均質(zhì)量。不過,單單重構(gòu)還不夠。好的設(shè)計在一開始就要帶入項目中,不能等出現(xiàn)問題后才試圖強行用于糟糕的結(jié)構(gòu)中。除了前面提到的構(gòu)建過程之外,本書要闡述的另一個基本要素就是設(shè)計。在我們深入構(gòu)建優(yōu)先這個未知領(lǐng)域之前,我要強調(diào)一點,構(gòu)建優(yōu)先并不只適用于JavaScript。多數(shù)人通常在后端語言(例如Java、C#或PHP)中使用我要介紹的原則,但在這里我把這些原則應(yīng)用到了JavaScript應(yīng)用的開發(fā)過程中。正如我前面提到的,客戶端代碼往往沒有得到應(yīng)有的關(guān)注和尊重,常常沒有適當?shù)販y試代碼,導致代碼有缺陷,或者致使代碼基難以閱讀和維護,最終受影響的是產(chǎn)品(以及開發(fā)者的工作效率)。對JavaScript來說,因為這門語言不需要編譯器,天真的開發(fā)者或許就以為根本不需要一套構(gòu)建過程。這樣的想法就像在黑暗中射擊一樣:在瀏覽器中執(zhí)行代碼之前,開發(fā)者不知道代碼是否能運行,也不知道代碼是否能像預期那樣做該做的事。然后,這些人可能還要手動把應(yīng)用部署到線上環(huán)境,再遠程登錄服務(wù)器,調(diào)整一些配置選項,讓應(yīng)用能運行。構(gòu)建優(yōu)先原則的核心法則構(gòu)建優(yōu)先原則的核心法則不僅鼓勵建立一套構(gòu)建過程,還鼓勵使用簡潔的方式設(shè)計應(yīng)用。下面概述了使用構(gòu)建優(yōu)先原則能獲得的好處:減少出錯的可能性,因為交互過程中沒有人類參與;自動執(zhí)行重復性的任務(wù),能提高工作效率;模塊化、可伸縮的應(yīng)用設(shè)計;能降低復雜度,讓應(yīng)用易于測試和維護;讓發(fā)布版本符合性能方面的最佳實踐;部署的代碼在發(fā)布前都經(jīng)過了測試。在圖1-1中,從上到下分為四個部分。構(gòu)建過程:使用自動化方式編譯和測試應(yīng)用。構(gòu)建的目的是便于持續(xù)開發(fā),還能調(diào)校應(yīng)用,讓發(fā)布版本得到最好的性能。設(shè)計:你的大部分時間都要用到設(shè)計上,在開發(fā)的過程中實現(xiàn)并改進架構(gòu)。在設(shè)計的過程中,你可能要重構(gòu)代碼,更新測試,確保組件能按照預期的方式運行。制定好構(gòu)建過程或準備好部署時,就要設(shè)計應(yīng)用的架構(gòu),并在代碼基中迭代開發(fā)。部署和環(huán)境:這兩部分的目的是自動執(zhí)行發(fā)布過程和配置不同的主機環(huán)境。部署過程的作用是把代碼變動傳送到主機環(huán)境中,而環(huán)境配置的作用是定義與應(yīng)用交互的環(huán)境和服務(wù),也包括數(shù)據(jù)庫。圖1-1概覽構(gòu)建優(yōu)先原則關(guān)注的四個方面:構(gòu)建過程,設(shè)計,部署和環(huán)境從圖1-1可以看出,使用構(gòu)建優(yōu)先原則開發(fā)應(yīng)用主要涉及兩方面:項目相關(guān)的過程,例如構(gòu)建和部署應(yīng)用;應(yīng)用代碼本身的設(shè)計和質(zhì)量,這方面在日常開發(fā)新功能時要不斷提升。這兩方面同等重要,而且二者之間相互依賴,這樣才能得到最好的結(jié)果。如果應(yīng)用設(shè)計得不好,過程再好也不管用。類似地,沒有合適的構(gòu)建和部署步驟,再好的設(shè)計也不能挽救前面所述的那種危機。和構(gòu)建優(yōu)先原則一樣,本書也分為兩部分。第一部分介紹構(gòu)建過程(開發(fā)和發(fā)布都適用)和部署過程,還會介紹如何配置環(huán)境。第二部分探討應(yīng)用本身的問題,說明如何實現(xiàn)簡潔明了的模塊化設(shè)計,還會介紹開發(fā)現(xiàn)代應(yīng)用時需要考慮的實用設(shè)計因素。下面兩節(jié)概述這兩部分要討論的概念。1.3構(gòu)建過程構(gòu)建過程涵蓋自動完成重復性的任務(wù),包括安裝依賴、編譯代碼、運行單元測試,以及執(zhí)行其他重要的操作。能一步執(zhí)行完所有需要執(zhí)行的任務(wù)(一步構(gòu)建)非常重要,這么做優(yōu)勢明顯。只要制定好了一步構(gòu)建方案,想執(zhí)行多少次就能執(zhí)行多少次,而且效果不變。這種特性叫冪等:不管執(zhí)行多少次,結(jié)果都一樣。圖1-2更詳細地列出了組成自動構(gòu)建和部署過程的重要步驟。圖1-2構(gòu)建優(yōu)先原則中的構(gòu)建和部署過程自動構(gòu)建過程的優(yōu)缺點自動構(gòu)建過程的最大優(yōu)點是只要需要隨時都能部署。功能開發(fā)完畢后立即就讓用戶使用,有利于收窄反饋循環(huán),這樣我們就能更好地預見應(yīng)該開發(fā)什么樣的產(chǎn)品。自動構(gòu)建過程主要的缺點是在真正獲益之前,要花一定的時間制定這個過程,可是自動化過程的好處絕對物超所值,例如我們能自動測試,得到的代碼質(zhì)量更高,開發(fā)流程更精益,而且部署流程更安全。一般來說,這個過程只需設(shè)置一次,以后隨時都能再次執(zhí)行,而且在開發(fā)的過程中還可以適當調(diào)整。1.構(gòu)建圖1-2的上半部分是構(gòu)建過程(如圖1-1所示)中構(gòu)建這一步的詳細說明,包含開發(fā)和發(fā)布兩方面的內(nèi)容。如果你關(guān)注的是開發(fā),就專注“調(diào)試”能力,我保證你想要一個無需干預就知道何時應(yīng)該執(zhí)行這些任務(wù)的構(gòu)建過程。這叫持續(xù)開發(fā)(ContinuousDevelopment,簡稱CD),在第3章中介紹。構(gòu)建過程中的“發(fā)布”和持續(xù)開發(fā)沒有關(guān)系,不過你應(yīng)該花時間優(yōu)化靜態(tài)資源,盡量讓應(yīng)用在生產(chǎn)環(huán)境中運行得更快。2.部署圖1-2的下半部分是圖1-1中部署過程的詳細說明,這部分將調(diào)試或發(fā)行版作為應(yīng)用發(fā)行版(我在操作流程中使用“發(fā)行版”這個詞是有特殊目的的,全書都會這樣用)部署到主機環(huán)境。打包代碼得到的發(fā)行版會和環(huán)境相關(guān)的配置(用于安全存儲機密信息,例如數(shù)據(jù)庫連接字符串和API密鑰,第3章會討論)一起,服務(wù)于應(yīng)用。第一部分專門討論構(gòu)建優(yōu)先原則中構(gòu)建方面的話題。第2章說明構(gòu)建任務(wù),教你如何使用Grunt編寫和配置任務(wù)。Grunt是任務(wù)運行程序,第一部分會一直使用這個工具。第3章介紹環(huán)境,如何安全配置應(yīng)用,還會介紹開發(fā)流程。第4章討論發(fā)布構(gòu)建版本時應(yīng)該執(zhí)行的任務(wù)。然后介紹部署方面的知識,如何每次推送到版本控制系統(tǒng)后都運行測試,以及如何在生產(chǎn)環(huán)境中監(jiān)控應(yīng)用。3.構(gòu)建過程的好處讀完第一部分后你就能自信地在自己的應(yīng)用中執(zhí)行下述操作了。自動執(zhí)行重復的任務(wù),例如編譯、簡化和測試。制作圖標子圖集表單,把對圖標的HTTP請求數(shù)減少到只有一個。這種子圖技術(shù)和其他的HTTP1.x優(yōu)化技巧在第2章討論,目的是提升頁面的加載速度和應(yīng)用的交付性能。輕松搭建新環(huán)境,忽略開發(fā)環(huán)境和生產(chǎn)環(huán)境之間的區(qū)別。相關(guān)文件改動后自動重啟Web服務(wù)器,以及重新編譯靜態(tài)資源。通過靈活的一步部署方案,支持多個環(huán)境。處理繁瑣的任務(wù)時,構(gòu)建優(yōu)先原則能節(jié)省人工,而且從一開始就能提升工作效率。構(gòu)建過程在構(gòu)建優(yōu)先原則中有重要意義,能打造出可維護的應(yīng)用,還能不斷減弱應(yīng)用的復雜度。本書第二部分會討論如何實現(xiàn)簡潔的應(yīng)用設(shè)計和架構(gòu),涵蓋應(yīng)用內(nèi)的復雜度管理,以及設(shè)計時為了提升質(zhì)量要考慮的因素。下面概述第二部分的內(nèi)容。1.4處理應(yīng)用的復雜度和設(shè)計理念不管使用什么語言開發(fā),如果想保證代碼在具有一定規(guī)模時仍能正常運行,就一定要做到以下幾點:模塊化、管理依賴、理解異步流、認真遵守正確的模式和測試。在第二部分你會學到不同的概念、技術(shù)和模式,運用這些知識后你的應(yīng)用就會變得更模塊化、更專注、更易于測試也更易于維護。在圖1-3中,從上到下就是第二部分的行文順序。圖1-3第二部分要討論的應(yīng)用設(shè)計和部署方面的內(nèi)容1.模塊化你會學習如何把應(yīng)用分成不同的組件,如何再把組件分成不同的模塊,然后在模塊中編寫作用單一的簡潔函數(shù)。模塊可以由外部包提供,由第三方開發(fā),也可以自己開發(fā)。外部包應(yīng)該交給包管理器處理,讓管理器管理版本,執(zhí)行升級操作,這樣就不用我們手動下載依賴了(例如jQuery)——整個過程都自動完成。在第5章你還會學到,模塊的依賴能在代碼中聲明,而不用從全局命名空間中獲取——這樣做能讓模塊更加獨立。模塊系統(tǒng)會利用這些信息,解析出所有的依賴,因此,為了能讓應(yīng)用正常運行,我們就不必按一定順序維護一長串<script>標簽了。2.設(shè)計你會學習如何分離關(guān)注點,使用“模型-視圖-控制器”模式分層設(shè)計應(yīng)用,進一步增強應(yīng)用的模塊化。在第7章我會告訴你關(guān)于共享渲染的知識,這個技術(shù)首先在服務(wù)器端渲染視圖,然后同一個單頁應(yīng)用中的后續(xù)請求都在客戶端渲染視圖。3.異步代碼我會教你使用不同的異步代碼流技術(shù),包括回調(diào)、Promise對象、生成器和事件,幫你馴服異步這頭猛獸。4.測試實踐第5章會討論模塊化的方方面面,學習閉包和模塊模式,還會討論不同的模塊系統(tǒng)和包管理器,并嘗試找出每種方案的優(yōu)勢。第6章會深入介紹JavaScript中的異步編程,告訴你如何避免編寫一周后就會讓人困惑的回調(diào),然后再學習Promise對象和ES6中的生成器API。第7章專門介紹各種模式和做法,例如如何寫出最好的代碼,對你來說jQuery是不是最好的選擇,以及如何編寫在客戶端和服務(wù)器中都能使用的JavaScript代碼。然后介紹Backbone這個MVC框架。記住,Backbone只是我用來向你介紹MVC知識的工具,并不是這方面唯一可用的框架。在第8章我們會介紹測試方案、自動化和很多客戶端JavaScript單元測試實例。你會學到如何為單個組件編寫單元測試,如何為整個應(yīng)用編寫集成測試。本書最后一章介紹RESTAPI設(shè)計,如何在前端使用RESTAPI,以及為了充分發(fā)揮REST架構(gòu)的功能而推薦使用的結(jié)構(gòu)。5.設(shè)計時要考慮的實際問題本書的目的是讓你在開發(fā)真正的應(yīng)用時考慮一些設(shè)計方面的實際問題,充分考慮后再選擇最合適的工具,始終注重過程和應(yīng)用本身的質(zhì)量。當你準備開發(fā)應(yīng)用時,首先要確定規(guī)模,選擇一個技術(shù)棧,再制定一個最小可行的構(gòu)建過程,然后開始開發(fā)應(yīng)用。你可能會使用MVC架構(gòu),或者在瀏覽器和服務(wù)器中都能使用的視圖渲染引擎,這些話題在第7章討論。在第9章你會學習開發(fā)API的重要知識,還會學習如何定義服務(wù)器端的視圖控制器和RESTAPI都能用到的后端服務(wù)。圖1-4簡要說明了使用構(gòu)建優(yōu)先原則開發(fā)時應(yīng)用的典型組織方式。圖1-4務(wù)實的架構(gòu)方式6.構(gòu)建過程從圖1-4的左上角開始看,可以看出,我們首先要制定一個構(gòu)建過程,這樣有助于開始著手架構(gòu)應(yīng)用,還要決定如何組織代碼基。定義一個模塊化的應(yīng)用架構(gòu)對可維護的代碼基來說是至關(guān)重要的,在第5章你會看出這一點。然后還要實現(xiàn)過程自動化,提供持續(xù)開發(fā)、持續(xù)集成和持續(xù)部署功能,以此增強架構(gòu)。7.設(shè)計和RESTAPI設(shè)計應(yīng)用本身,以及能顯著提升可維護性的RESTAPI時,一定要明確每個組件的作用,讓組件之間形成正交關(guān)系(意思是,組件之間在任何方面都不會爭奪資源)。在第9章我們會探討一種設(shè)計應(yīng)用的多層方式,我們會嚴格定義各層以及層與層之間的通信路徑,把Web界面與數(shù)據(jù)和業(yè)務(wù)邏輯明確地隔開。8.積極測試設(shè)計好構(gòu)建過程和架構(gòu)后,我們要積極測試,關(guān)注可靠性方面的問題。我們要探索持續(xù)集成,每次把代碼推送到版本控制系統(tǒng)后都要執(zhí)行測試;或許還要探索持續(xù)開發(fā),每天多次把應(yīng)用部署到生產(chǎn)環(huán)境。我們還會討論容錯方面的知識,例如記錄日志、監(jiān)控和搭建集群。這些內(nèi)容會在第4章概述,為的是讓生產(chǎn)環(huán)境更穩(wěn)健,至少在出問題時能提醒你。在這個過程中我們會編寫測試,調(diào)整構(gòu)建過程,還會微調(diào)代碼。對你來說,這是個好機會,能讓你仔細審視構(gòu)建優(yōu)先原則。駕輕就熟后,再開始學習構(gòu)建優(yōu)先原則的細節(jié)。1.5鉆研構(gòu)建優(yōu)先原則質(zhì)量是構(gòu)建優(yōu)先原則的基石,這個原則采取的每項措施都是為了一個簡單的目標,即提升代碼的質(zhì)量,并使用更合理的方式組織代碼。在本節(jié)你要學習代碼質(zhì)量方面的知識,以及如何在命令行使用檢查代碼質(zhì)量的工具:lint程序。衡量代碼的質(zhì)量是向編寫結(jié)構(gòu)良好的應(yīng)用邁出的第一步。盡早這么做容易讓代碼基符合一定的質(zhì)量標準,所以接下來我們就要來做這件事。學會使用lint程序后,在第2章我會介紹如何使用Grunt。本書會一直使用這個構(gòu)建工具制定自動化構(gòu)建過程。使用Grunt能在構(gòu)建過程中檢查代碼質(zhì)量,以防你忘記做這件事。Grunt:實現(xiàn)自動化的工具第一部分會大量使用Grunt,第二部分也會適量使用。我們使用這個工具實現(xiàn)構(gòu)建過程。選擇Grunt是因為它很流行,而且易于學習,能滿足大多數(shù)人的需求:完全支持Windows;使用時只需少量的JavaScript知識,而且易于安裝和運行。記住,Grunt只是一種工具,使用它能輕易實現(xiàn)本書介紹的構(gòu)建過程,并不是說Grunt始終是最佳選擇。為了明確這一點,我會把Grunt和另外兩個工具做對比:一個是npm,這是一個包管理器,也能當作簡單的構(gòu)建工具使用;另一個是Gulp,這是一個由代碼驅(qū)動的構(gòu)建工具,和Grunt有很多共同點。如果你對其他構(gòu)建工具(例如Gulp)好奇,或者想把npmrun當成構(gòu)建系統(tǒng)使用,請閱讀附錄C,其中詳細說明了如何選擇合適的構(gòu)建工具。lint程序是檢查代碼質(zhì)量的工具,特別適合用來檢查使用解釋型語言(例如JavaScript)編寫的程序。我們不用打開瀏覽器檢查代碼是否有句法錯誤,在命令行中執(zhí)行l(wèi)int程序就能找出代碼中潛在的問題,例如未聲明的變量、缺少分號或句法錯誤。不過lint程序也不是萬能的,它檢測不到代碼中的邏輯問題,只能提醒句法和風格錯誤。1.5.1檢查代碼質(zhì)量lint程序能判斷給定的代碼片段中有沒有句法錯誤,還能實施一些JavaScript編程的最佳實踐規(guī)則。第二部分的開頭第5章,在討論模塊化和依賴管理時會介紹這些最佳實踐。大約10年前,DouglasCrockford發(fā)布了JSLint。這個工具檢查代碼時很嚴格,會報告代碼中所有的小問題。lint程序的作用是幫助我們提升代碼的整體質(zhì)量。lint程序直接在命令行中執(zhí)行,能報告代碼片段或文件中潛在的問題。這么做有個額外好處,我們甚至不用執(zhí)行代碼就能找出問題。對JavaScript代碼來說,這個過程特別有用,因為在某種程度上,lint程序可以當做編譯器,盡量確保代碼能被JavaScript引擎解釋。除此之外,我們還能配置lint程序,讓它發(fā)現(xiàn)太復雜的代碼時提醒我們,比如說行數(shù)太多的函數(shù),可能會讓別人困惑的晦澀結(jié)構(gòu)(對JavaScript來說,例如with塊,new語句,或者過度使用this),諸如此類的代碼風格問題。以下述代碼片段為例(位于在線示例的ch01/01_lint-sample文件夾中):
functioncompose_ticks_count(start){
start||start=1;
this.counter=start;
returnfunction(time){
ticks=+newDate;
returnticks+'_'+this.counter++
}
}
這么一小段代碼中有很多問題,不過可能很難發(fā)現(xiàn)。使用JSLint分析這段代碼時,既會得到預料之中的結(jié)果,也會得到意料之外的結(jié)果。JSLint會提醒你,變量在使用之前必須先聲明,而且缺少分號。如果使用其他lint程序,可能還會抱怨你使用了this關(guān)鍵字。大多數(shù)lint程序都會抱怨你使用了||運算符,而沒使用更易于閱讀的if語句。你可以在線檢查這段代碼。2圖1-5是使用Crockford的工具檢查得到的結(jié)果。2訪問\h/,然后輸入這段代碼。這是最先出現(xiàn)的JavaScriptlint工具,由Crockford維護。圖1-5在一段代碼中發(fā)現(xiàn)的錯誤對編譯型語言來說,這些錯誤類型在編譯代碼時就能捕獲,因此不需要使用lint工具。而JavaScript沒有編譯器,這是由這門語言的動態(tài)特性決定的。這種方式無疑很強大,但和編譯型語言相比卻更容易出錯,一開始代碼甚至無法執(zhí)行。JavaScript代碼無需編譯,由引擎解釋執(zhí)行,例如V8(GoogleChrome使用的引擎)和SpiderMonkey(MozillaFirefox使用的引擎)。雖然有些引擎(最著名的是V8引擎)會編譯JavaScript代碼,但在瀏覽器之外享受不到靜態(tài)代碼分析的好處。3像JavaScript這樣的動態(tài)語言有個缺點,執(zhí)行代碼時無法確保代碼一定能正常運行。雖然如此,但是使用lint工具能大大降低這種不確定性。而且JSLint還會建議我們不要使用某種編程風格,例如使用了eval,沒聲明變量,語句塊缺少花括號等。3在終端使用Node.js能獲得這個功能,但V8引擎檢測到句法問題時已經(jīng)太晚了,此時程序會崩潰。Node.js是服務(wù)器端JavaScript平臺,也運行在V8引擎之上。你發(fā)現(xiàn)前面代碼片段中的函數(shù)有什么問題了嗎?看一下本書的配套代碼示例(ch01/01_lint-sample文件夾),驗證一下自己的答案。提示:問題是有重復。修正后的版本也在源碼示例中,你一定要看一下好的寫法。對本書配套源碼的說明本書的配套源碼包含很多重要的信息,例如上述示例函數(shù)有一個調(diào)整后的版本,能通過lint程序的驗證,而且有很多注釋,便于理解改動的部分。這個示例也證明了lint程序不是萬能的。本書配套源碼中的其他代碼示例也有類似的建議和重要的信息,所以一定要看一下!配套源碼中的示例按章組織,而且和在書中出現(xiàn)的順序一致。很多示例在書中只有簡單討論,不過在配套源碼中所有代碼示例都有完整的注釋,拿來就可以使用。書中的代碼和配套源碼之間出現(xiàn)這種差異是因為,有時我想說明某個話題,但可能涉及的代碼太多,在書中不能全部列出。遇到這種情況時,我不想太過偏離要講解的概念,又想給你提供真實的代碼。使用這種方式,在閱讀本書的過程中能讓你集中精力學習,瀏覽代碼示例時再集中精力去試驗。通常,寫完代碼后第一件事就是使用lint程序檢查,lint程序發(fā)現(xiàn)不了的問題則交給單元測試。這并不意味著沒必要使用lint程序,而是說僅使用lint程序是不夠的。單元測試的作用是確保代碼的表現(xiàn)與預期一樣。單元測試在第8章討論,你會學習如何為第二部分編寫的代碼編寫測試。第二部分的內(nèi)容旨在說明如何編寫模塊化、可維護和可測試的JavaScript代碼。接下來我們要從零開始制定一個構(gòu)建過程。我們從簡單的任務(wù)開始,先編寫一個運行l(wèi)int程序檢查代碼的任務(wù),然后在命令行中運行這個任務(wù),就像使用編譯器編譯代碼的過程一樣。你會學著養(yǎng)成習慣,每次修改代碼后都執(zhí)行這個任務(wù),查看代碼是否能夠通過lint程序的檢查。第3章會教你如何自動執(zhí)行這個任務(wù),這樣就不必每次都手動執(zhí)行了。不過現(xiàn)在可以手動執(zhí)行?!叭绾沃苯釉诿钚兄惺褂肑SLint這樣的lint工具呢?”我很高興你能提出這個問題。1.5.2在命令行中使用lint工具把任務(wù)添加到構(gòu)建過程最常見的方式之一,是在命令行中執(zhí)行這個任務(wù)。如果能在命令行中執(zhí)行任務(wù),那么這個任務(wù)就能輕易集成到構(gòu)建過程中。下面介紹如何使用JSHint4檢查你的軟件。4關(guān)于JSHint更多的信息,請訪問\h。JSHint是一個命令行工具,使用Node.js編寫,用于檢查JavaScript文件和代碼片段。Node.js是一個使用JavaScript開發(fā)應(yīng)用的平臺,如果你想簡單了解Node.js的基礎(chǔ)知識,可以翻到附錄A,在這篇附錄中我說明了什么是模塊,以及模塊的工作方式。如果你想深入學習Node.js,可以閱讀MikeCantelon等人寫的《Node.js實戰(zhàn)》。掌握Node.js的知識也有助于使用下一章我們選定的構(gòu)建工具——Grunt。Node.js簡介Node.js是相對較新的平臺,你肯定聽說過。Node最初于2009年發(fā)布,遵從事件驅(qū)動和單線程模式,能高效并發(fā)處理請求。從這方面來看,Node和Nginx的設(shè)計理念一致。Nginx是高度可伸縮的多用途反向代理服務(wù)器,非常流行,作用是伺服靜態(tài)內(nèi)容,以及把請求轉(zhuǎn)發(fā)給應(yīng)用服務(wù)器(例如Node)。Node.js廣受贊譽,尤其是對前端工程師來說,特別容易上手,因為大致而言,它只不過是在服務(wù)器端運行的JavaScript。Node.js還能把前端完全從后端抽象出來5,只通過數(shù)據(jù)和RESTAPI接口交互。我們在第9章就會使用這樣的方式設(shè)計和開發(fā)應(yīng)用。5關(guān)于把前端從后端抽象出來的更多信息,請訪問\hhttp://bevacqua.io/bf/node-frontend。1.安裝Node.js和JSHint安裝Node.js和JSHint命令行界面(Command-lineInterface,簡稱CLI)的步驟如下。安裝Node.js的其他方式和排除故障的方法參見附錄A。訪問\h,點擊頁面中的“INSTALL”按鈕(如圖1-6),下載最新版Node.js。圖1-6Node.js的網(wǎng)站運行下載得到的文件,按照安裝說明安裝。安裝完成后會得到一個命令行工具,名為npm(NodePackageManager的簡稱),因為這個工具和Node.js是捆綁在一起的。npm是個包管理器,在終端里使用,用于安裝、發(fā)布和管理Node.js項目用到的模塊。包可以安裝在各個項目中,也可以全局安裝——這樣更便于從終端調(diào)用。其實,這兩種安裝方式之間的區(qū)別是,全局安裝的包存放在環(huán)境變量PATH對應(yīng)的文件夾中,而另一種安裝方式把包存放在一個名為node_modules的文件夾中,而這個文件夾位于執(zhí)行安裝命令所在的文件夾中。為了讓項目自成一體,都推薦把包安裝在項目中。不過,對JSLint這樣的實用工具來說,我們希望在整個系統(tǒng)中都能使用,因此全局安裝更合適。修飾符-g能讓npm全局安裝JSHint。使用這種方式安裝,我們能在命令行中通過jshint命令使用JSHint。打開你最喜歡的終端,執(zhí)行npminstall-gjshint命令,如圖1-7所示。如果安裝失敗,可能要使用sudo提升權(quán)限,例如sudonpminstall-gjshint。此行文本用于列表編號,不因該出現(xiàn)在正文中。圖1-7使用npm安裝JSHint執(zhí)行jshint--version。這個命令應(yīng)該輸出JSHint的版本號,如圖1-8所示。你看到的版本號可能和圖中不一樣,因為開發(fā)活躍的包經(jīng)常會變更版本號。圖1-8在終端里驗證jshint可用下一節(jié)說明如何檢查代碼。2.檢查代碼你現(xiàn)在應(yīng)該在系統(tǒng)中安裝好了JSHint,而且已經(jīng)確認可以在終端里調(diào)用。如果想使用JSHint檢查代碼,可以使用cd命令進入項目的根目錄,然后輸入jshint.(點號告訴JSHint檢查當前文件夾里的所有文件)。如果執(zhí)行的時間太長,或許要加上--excludenode_modules選項,告訴JSHint只檢查自己編寫的代碼,忽略通過npminstall安裝的第三方代碼。命令執(zhí)行完畢后,你會看到一份詳細報告,說明代碼的狀況。如果代碼中有問題,這個工具會報告預期的結(jié)果和出現(xiàn)問題的行號,然后退出,返回一個錯誤碼。如果通不過檢查,我們可以使用這個錯誤碼中斷構(gòu)建過程。只要有構(gòu)建任務(wù)沒得到預期的輸出,整個構(gòu)建過程就應(yīng)該中止。這么做有很多好處,出錯后不會繼續(xù)運行,在問題解決前不會完成整個構(gòu)建過程。圖1-9顯示的是檢查某段代碼后得到的結(jié)果。圖1-9在命令行中使用JSHint檢查代碼安裝好JSHint之后你可能就想收工了,因為這是你唯一的任務(wù)??墒牵绻朐跇?gòu)建過程中增加任務(wù),還不方便。你或許想在構(gòu)建過程中增加一步,運行單元測試,這時就會遇到問題,因為你現(xiàn)在至少要執(zhí)行兩個命令:一個是jshint,另一個是運行測試的命令。這樣做的伸縮性不好,你要記住如何使用jshint,還有很多其他命令及其參數(shù),太麻煩,難記,而且容易出錯。你肯定不想損失五億美元吧!那么你最好把構(gòu)建任務(wù)放在一起,雖然現(xiàn)在只有一個任務(wù),但很快就會變多。制定構(gòu)建過程時要考慮自動化,避免重復各個步驟,以節(jié)省時間。每門語言都有多個專用的構(gòu)建工具,而且多數(shù)情況下都有一個工具比較出眾,使用范圍比其他工具廣。對JavaScript來說,Grunt是最受歡迎的構(gòu)建工具之一,有成千上萬個插件(輔助構(gòu)建任務(wù))供使用。如果你要為其他語言制定構(gòu)建過程,或許需要自己搜索,找到合適的工具。雖然本書編寫的構(gòu)建任務(wù)是針對JavaScript的,而且使用Grunt,不過我講的原則應(yīng)該能應(yīng)用于任何語言和構(gòu)建工具。翻到第2章,看看如何把JSHint集成到Grunt中,以此開啟制定構(gòu)建過程的旅程。1.6總結(jié)本章概覽了本書后面幾章要深入探討的概念。下面列出你在本章學到的內(nèi)容?,F(xiàn)代JavaScript應(yīng)用開發(fā)是有問題的,因為缺少對設(shè)計和架構(gòu)的重視。使用構(gòu)建優(yōu)先原則能得到自動化的過程,設(shè)計出可維護的應(yīng)用,而且鼓勵思考你所開發(fā)的應(yīng)用。學會了使用lint程序檢查代碼,不使用瀏覽器就提升了代碼質(zhì)量。在第一部分你會學習構(gòu)建過程、部署和環(huán)境配置的所有知識。你將使用Grunt開發(fā)構(gòu)建過程,在附錄C中還能學習可以使用的其他工具。第二部分專門說明應(yīng)用設(shè)計的復雜性。模塊化、異步代碼流、應(yīng)用和API設(shè)計,以及可測試性都有一定的作用,會在第二部分介紹。說到使用構(gòu)建優(yōu)先原則設(shè)計應(yīng)用的好處,現(xiàn)在你只看到了皮毛,還有很多知識要學。下面我們進入第2章,討論構(gòu)建過程中最可能要執(zhí)行的任務(wù),再通過示例說明如何使用Grunt實現(xiàn)這些任務(wù)。
第2章編寫構(gòu)建任務(wù),制定流程本章內(nèi)容理解在構(gòu)建過程中應(yīng)該做什么學習關(guān)鍵的構(gòu)建任務(wù)使用Grunt執(zhí)行關(guān)鍵的構(gòu)建任務(wù)使用Grunt配置構(gòu)建流程自己編寫Grunt任務(wù)前一章簡單概述了構(gòu)建優(yōu)先原則,還稍微提到了一個使用lint程序檢查代碼的任務(wù)。本章我們要介紹一些常見的構(gòu)建任務(wù),還會介紹一些高級任務(wù)。我會告訴你這些任務(wù)的使用場景,以及使用它們的原因,然后介紹如何使用Grunt實現(xiàn)。學習理論的過程可能很枯燥,但如果你想使用Grunt之外的任務(wù)運行程序——我相信最終你會這么做的——理論就顯得尤為重要了。Grunt是由配置驅(qū)動的構(gòu)建工具,能輕易執(zhí)行復雜的任務(wù),只要你知道你想做什么就行。使用Grunt能制定出我在第1章說過的那種工作流程,提高開發(fā)效率,并優(yōu)化發(fā)布流程。而且在部署過程中Grunt也能提供幫助,這一點將在第4章詳述。本章關(guān)注的是構(gòu)建任務(wù),不會教你Grunt的全部知識。只要理解了工具目標背后的概念,就能學會使用工具,但如果不理解這些基本概念,肯定學不會如何正確使用其他工具。如果你想深入學習Grunt,可以閱讀附錄B。閱讀該附錄對理解本章的內(nèi)容沒有幫助,不過這篇附錄講解了第一部分會用到的Grunt功能。本章首先簡要介紹Grunt及其核心概念,剩下的內(nèi)容則教你構(gòu)建任務(wù)的知識,還會教你使用一些不同的工具。我們會學習預處理任務(wù),例如把代碼編譯成另一種語言,還會學習后處理任務(wù)如簡化靜態(tài)資源、創(chuàng)建圖像子圖集,以及代碼完整性任務(wù)如運行JavaScript單元測試、使用lint程序檢查CSS代碼。隨后我們會學習如何使用Grunt自己編寫任務(wù),我會舉一個案例,教你編寫一套數(shù)據(jù)庫模式更新任務(wù),這個任務(wù)還支持回滾操作。我們開始學習吧!2.1介紹GruntGrunt1是一個任務(wù)運行程序,能幫你執(zhí)行命令、運行JavaScript代碼,還能使用完全由JavaScript編寫的代碼配置各個任務(wù)。Grunt的構(gòu)建概念借鑒自Ant,讓你使用JavaScript定義自己的流程。1關(guān)于Grunt的更多信息請訪問\hhttp://bevacqua.io/bf/grunt,也可以閱讀附錄B。圖2-1是從較高層次上對Grunt進行的詳細解析,展示了如何配置Grunt以及定義構(gòu)建任務(wù)時需要理解的關(guān)鍵概念。任務(wù)用于執(zhí)行操作。目標定義任務(wù)的上下文。任務(wù)的配置決定具體的任務(wù)和目標組合使用哪些選項。圖2-1Grunt一覽:任務(wù)和目標都在配置中Grunt任務(wù)使用JavaScript代碼配置。大多數(shù)情況下,配置都是通過把一個對象傳給grunt.initConfig方法完成的。在配置中可以指明任務(wù)會作用于哪些文件,還能傳入一些選項,調(diào)整某個任務(wù)目標的行為。對運行單元測試的任務(wù)來說,在本地開發(fā)時你可能只想運行幾個測試,或者在發(fā)布用于生產(chǎn)環(huán)境的版本前運行所有測試。圖2-2展示了用于配置的JavaScript代碼,詳細說明了grunt.initConfig方法及其約定。枚舉文件時可以使用通配符,而使用這種模式叫通配。2.2.2節(jié)會詳細說明通配模式。任務(wù)可以從插件中導入。插件是Node模塊(設(shè)計良好、自成一體的代碼),包含一個或多個Grunt任務(wù)。你只需要知道插件能使用哪些配置,任務(wù)本身則由插件處理。本章會大量使用插件。22Grunt插件可以在線搜索,地址是\h/plugins。你也可以自己編寫任務(wù),2.4節(jié)和2.5節(jié)會介紹方法。Grunt自帶了一個CLI(Command-LineInterface,命令行接口),名為grunt,提供了一個簡單的接口,用于直接在命令行中執(zhí)行構(gòu)建任務(wù)。下面我們來安裝Grunt。圖2-2Grunt任務(wù)配置的代碼詳解圖。每個任務(wù)和任務(wù)目標都單獨配置。2.1.1安裝Grunt你應(yīng)該已經(jīng)安裝了npm,因為在第1章安裝lint工具JSHint時安裝了Node.js,而Node.js中就有包管理器npm。Grunt的安裝方法很簡單,在終端里執(zhí)行下述命令就能安裝grunt3的CLI:3關(guān)于Grunt的更多信息,請訪問\hhttp://bevacqua.io/bf/grunt。
npminstall-ggrunt-cli
-g標志表明這個包要全局安裝,這樣不管當前工作目錄是什么,都能在終端里執(zhí)行g(shù)runt命令。找到本書配套源碼中有注解的示例本書的配套源碼中有完整可用的示例。這一節(jié)的示例在ch02目錄里的01_intro-to-grunt文件夾中,本章其他的示例也在ch02目錄里。大部分示例都有代碼注解,在你產(chǎn)生困惑時能幫助你理解。接下來你需要創(chuàng)建一個名為package.json的清單文件。這個文件用于描述Node.js項目,指明項目依賴的包列表,還有一些元信息,例如項目名稱、版本、描述和主頁。為了能在你的項目中使用Grunt,你需要把它添加到package.json文件中,作為一個開發(fā)依賴。之所以作為開發(fā)依賴,是因為除了本地開發(fā)環(huán)境之外,在其他地方用不到Grunt。你可以創(chuàng)建一個最簡單的package.json文件,寫入下述JSON代碼,并把這個文件保存到項目的根目錄中:
{}
這樣就行了。只要package.json文件存在,而且包含一個有效的JSON對象,哪怕是空對象{}也行,Node包管理器(npm)就能向其中添加依賴。1.在本地安裝Grunt接下來要安裝grunt包。這一次我們不能使用-g修飾符了,因為現(xiàn)在要在本地安裝Grunt,而不是全局安裝4——這也就是為什么要創(chuàng)建package.json文件的原因?,F(xiàn)在我們要使用--save-dev修飾符,指明這是個開發(fā)依賴。4Grunt包和任務(wù)插件都要求在本地安裝Grunt,這樣代碼才能在不同的設(shè)備中正常運行,因為在package.json文件中無法包含全局安裝的包。我們要執(zhí)行的命令是:npminstall--save-devgrunt。npm安裝完這個包后,package.json文件的內(nèi)容會變成類似下面這樣:
{
"devDependencies":{
"grunt":"~0.4.1"
}
而且,Grunt模塊會安裝到項目的node_modules目錄里。Grunt用到的所有模塊都會安裝在這個目錄中,而且都會在包清單文件中列出來。2.創(chuàng)建Gruntfile.js文件最后一步是創(chuàng)建Gruntfile.js文件。Grunt使用這個文件加載可用的任務(wù),并使用所需的參數(shù)配置任務(wù)。下述代碼是最簡單的Gruntfile.js模塊:
module.exports=function(grunt){
grunt.registerTask('default',[]);//注冊default任務(wù)別名
};
這個文件看似平常,但有幾點要注意。Gruntfile.js文件是符合CommonJS模塊規(guī)范5的Node模塊,因此在其他文件中無法立即訪問這個文件中的代碼。這個文件中的module是個隱式對象,不像瀏覽器中的window,是個全局對象。導入其他模塊時,得到的只是module.exports提供的公開接口。5請訪問\hhttp://bevacqua.io/bf/commonjs閱讀CommonJS模塊規(guī)范。Node.js模塊Node.js模塊采用的規(guī)范CommonJS,在附錄A中有進一步介紹。第5章說明模塊化時還會討論CommonJS。附錄B是對附錄A的擴充,能增強你對Grunt的理解。上述代碼片段中g(shù)runt.registerTask那行告訴Grunt定義一個默認任務(wù),在命令行中執(zhí)行g(shù)runt且不帶任何參數(shù)時執(zhí)行的就是這個任務(wù)。數(shù)組表明這是個任務(wù)別名,只要數(shù)組中有任務(wù),就會執(zhí)行其中所有的任務(wù)。例如,設(shè)為['lint','build']時會執(zhí)行l(wèi)int任務(wù)和build任務(wù)?,F(xiàn)在執(zhí)行g(shù)runt命令沒有任何作用,因為我們注冊的別名是空的。你肯定迫切地想設(shè)置第一個Grunt任務(wù),那就來設(shè)置吧。2.1.2設(shè)置第一個Grunt任務(wù)設(shè)置Grunt任務(wù)的第一步是安裝能滿足需求的插件,然后添加配置,最后再運行任務(wù)。Grunt插件一般以npm模塊的形式分發(fā),這些模塊是別人發(fā)布的JavaScript代碼,你可以直接使用。我們要先安裝Grunt的JSHint插件,安裝了這個插件后就能使用Grunt運行JSHint了。注意,這里完全不需要第1章安裝的CLI工具jshint,因為Grunt插件包含運行JSHint所需的一切,它會自動安裝jshintCLI。下述命令會從npm源獲取JSHint插件,安裝到node_modules目錄中,然后再把這個插件添加到package.json文件中,作為一個開發(fā)依賴:
npminstall--save-devgrunt-contrib-jshint
接下來我們要修改Gruntfile文件,讓Grunt使用lint程序檢查這個文件,因為它也是個JavaScript文件。你要告訴Grunt,讓它加載包含檢查任務(wù)的JSHint插件包,還要更新default任務(wù),這樣在命令行中只執(zhí)行g(shù)runt就能檢查代碼了。配置Gruntfile.js文件的方式如下述代碼清單所示(在代碼示例的ch02/01_intro-to-grunt文件夾里)。代碼清單2.1Gruntfile.js文件示例
module.exports=function(grunt){<導出的函數(shù)有個名為grunt的參
grunt.initConfig({<任務(wù)在initConfig方法中配置,傳入的是一個描述配置信息的對象。
jshint:['Gruntfile.js']
});
grunt.loadNpmTasks('grunt-contrib-jshint');<插件要分別載入Grunt。
grunt.registerTask('default',['jshint']);<注冊default別名,執(zhí)行jshint任務(wù)。
};
安裝插件包后都要在Gruntfile.js文件中使用grunt.loadNpmTasks將其載入Grunt,如代碼清單2.1所示。Grunt要從包中加載任務(wù),這樣才能配置和執(zhí)行任務(wù)。隨后你要配置任務(wù),方法是把一個對象傳給grunt.initConfig方法。每個任務(wù)插件都要配置,介紹各個插件時我都會告訴你怎么配置。最后,我還更新了default別名,讓它執(zhí)行jshint任務(wù)。default別名用于定義沒有任何參數(shù)的grunt命令執(zhí)行哪些任務(wù)。執(zhí)行g(shù)runt命令得到的輸出如下面的截圖所示。圖2-3我們的第一個Grunt任務(wù)及其輸出。我們的代碼通過了檢查,也就是說沒有句法錯誤。2.1.3使用Grunt管理構(gòu)建過程現(xiàn)在我們實現(xiàn)的功能幾乎和第1章結(jié)束時的一樣,也就是能使用JSHint檢查JavaScript代碼了,不過這次有所不同。Grunt能幫我們制定一個成熟的構(gòu)建過程,這對構(gòu)建優(yōu)先原則至關(guān)重要。省下的精力能讓我們專注于為本地開發(fā)環(huán)境中的構(gòu)建、診斷或構(gòu)建用戶最終要使用的產(chǎn)品這個過程編寫不同的任務(wù)。我們來看看構(gòu)建任務(wù)的幾個特性。前面設(shè)置的lint任務(wù)是個基礎(chǔ)。在閱讀本書第一部分的過程中,你的理解會越來越深,有了這個基礎(chǔ)就能寫出更強大的構(gòu)建任務(wù)。這個任務(wù)清楚地表明了構(gòu)建任務(wù)的一個基本特性:絕大多數(shù)情況下,任務(wù)都是冪等的,即重復執(zhí)行任務(wù)不會得到不同的結(jié)果。對這個lint任務(wù)來說,這可能意味著,只要不修改源碼,每次執(zhí)行都能得到相同的提醒。通常,構(gòu)建任務(wù)都會操作一個或多個輸入文件。有了冪等特性,加之我們不再手動執(zhí)行任何操作了,這樣得到的結(jié)果會更加一致。1.創(chuàng)建工作流程和持續(xù)開發(fā)構(gòu)建過程中的任務(wù)要按照明確定義的順序執(zhí)行才能實現(xiàn)特定的目標,例如準備一個發(fā)布版本。我們在第1章提到過,這叫工作流程。某些任務(wù)在具體的工作流程中是可有可無的,有些則可能會提供一些幫助。例如,在本地開發(fā)環(huán)境中沒必要優(yōu)化圖像,把圖像變得更小,因為這么做不能顯著提升性能,所以最好跳過這個任務(wù)。但不管在開發(fā)流程還是發(fā)布流程中,你或許都想執(zhí)行l(wèi)int任務(wù),以確保代碼沒問題。圖2-4能幫助你理解構(gòu)建過程中涉及的開發(fā)、發(fā)布和部署方面的任務(wù)。圖中展示了各個任務(wù)之間的關(guān)系,以及如何把任務(wù)組合起來,構(gòu)成不同的工作流程。2.開發(fā)流程看一眼這幅圖最上面一行的內(nèi)容就能發(fā)現(xiàn),效率和監(jiān)視變動是開發(fā)流程的重點,而在發(fā)布流程中則毫不重要,甚至還可能成為干擾。你可能還會注意到,這兩個流程都構(gòu)建出了應(yīng)用,不過開發(fā)流程得到的應(yīng)用是針對持續(xù)開發(fā)的,我們在第3章會詳述這一點。3.發(fā)布流程在發(fā)布流程中,我們關(guān)注的是性能優(yōu)化,以及構(gòu)建整體測試良好的應(yīng)用。和開發(fā)流程稍有不同,這個流程執(zhí)行的任務(wù)重視的是減少應(yīng)用占用的字節(jié)量。4.部署流程部署流程完全不構(gòu)建應(yīng)用,而是直接使用前兩個流程準備好的構(gòu)建版本,將其傳到主機環(huán)境中。第4章會詳細說明部署流程。圖2-4構(gòu)建和部署流程中關(guān)注的重點有所不同任何合理的構(gòu)建流程都要自動執(zhí)行其中的每一步,否則就無法提升效率、減少出錯的可能性。開發(fā)時,我們在文本編輯器和瀏覽器之間來回切換,不用自己執(zhí)行構(gòu)建過程。這叫作持續(xù)開發(fā),因為這不需要打開shell,輸入命令編譯應(yīng)用。第3章會教你如何使用文件監(jiān)視功能和其他機制實現(xiàn)持續(xù)開發(fā)。部署應(yīng)用的過程應(yīng)該和構(gòu)建流程分開,但也要自動化,一步就能構(gòu)建并部署應(yīng)用。類似地,伺服應(yīng)用這一步也應(yīng)該嚴格和構(gòu)建過程分開。下一節(jié)我們會詳細說明如何使用Grunt執(zhí)行構(gòu)建任務(wù)。具體而言,我們會先從預處理任務(wù)開始,例如把LESS文件編譯成CSS文件,然后再介紹后處理任務(wù),例如打包和簡化,以幫你優(yōu)化和調(diào)整發(fā)布版本。2.2預處理和靜態(tài)資源優(yōu)化談到開發(fā)Web應(yīng)用,不可避免地要討論預處理。我們通常會使用瀏覽器原生不支持的語言,因為這些語言提供了CSS(例如廠商前綴)、HTML或JavaScript原本不支持的功能,能避免重復性的工作。本節(jié)的重點不是教你LESS(一個CSS預處理器,下一節(jié)會介紹)或CSS,因為這兩門語言有很多專門的教程。本節(jié)的重點是讓你了解使用預處理語言的巨大好處。預處理和CSS無關(guān)。預處理器能把使用一門語言編寫的代碼轉(zhuǎn)換成多種目標語言。例如,強大且富有表現(xiàn)力的LESS語言在構(gòu)建時能轉(zhuǎn)換成純正的CSS。不同人使用預處理器的目的各異,但基本上可分這么幾類:為了提升效率、減少重復或使用更舒適的句法。后處理任務(wù),例如簡化和打包,基本上是為了優(yōu)化發(fā)布版本,但這些任務(wù)和預處理任務(wù)聯(lián)系緊密,所以這一節(jié)也會介紹到它。我們首先介紹使用LESS做預處理,然后介紹Grunt用來匹配文件路徑的通配模式,最后介紹打包和簡化,它們能優(yōu)化應(yīng)用的性能,供用戶使用。讀完本節(jié)之后,你會更加理解如何使用更合適的語言預處理靜態(tài)資源,以及如何對靜態(tài)資源作后處理,以提升性能,增強用戶體驗。2.2.1詳述預處理現(xiàn)今,在Web開發(fā)中使用語言預處理器是相當普遍的現(xiàn)象。除非過去十年你隱居了,否則你應(yīng)該知道預處理器能幫助我們編寫更簡潔的代碼,就像第1章介紹的lint程序一樣。不過我們要多做些事情才能讓預處理器發(fā)揮作用。說白了,如果使用能轉(zhuǎn)換成其他語言的語言編寫代碼,要增加預處理這一步,它用來轉(zhuǎn)換代碼。你不想使用目標語言編寫代碼可能有這幾個原因:目標語言太啰嗦、太容易出錯,或者你就是不喜歡那門語言。此時,這些高級語言就發(fā)揮作用了,它們能讓代碼簡潔明了。不過使用這些高級語言編寫代碼也要付出代價:瀏覽器不理解這些語言。因此,在前端開發(fā)中最常見的任務(wù)之一就是把使用高級語言編寫的代碼編譯成瀏覽器能理解的代碼,即JavaScript和CSS樣式。有時預處理器還能提供Web的原生語言(HTML、CSS和JavaScript)沒有的實用功能。例如,有些CSS預處理器提供了必要的工具,我們不必再為每種瀏覽器編寫專用的樣式。預處理語言能消除瀏覽器之間的差異,提高我們的效率,讓工作變得更有趣。1.LESS:簡約而不簡單下面以LESS為例介紹預處理器。LESS是一門強大的語言,是CSS的一個變種。它是遵從應(yīng)用設(shè)計的DRY(Don'tRepeatYourself,不要自我重復)原則而設(shè)計,寫出的代碼重復性較少。使用純粹的CSS往往要不斷自我重復,為所有的廠商前綴指定相同的值,盡量讓應(yīng)用的樣式支持更多的瀏覽器。我們以CSS屬性border-radius為例來說明這個問題。這個屬性的作用是為元素加上圓角樣式,使用純粹的CSS要像下述代碼清單這樣編寫樣式。代碼清單2.2使用純粹的CSS實現(xiàn)圓角樣式
.slightly-rounded{
-webkit-border-radius:2px;<需要使用“廠商前綴”才能讓某些瀏覽器應(yīng)用特定的樣式。
-moz-border-radius:2px;
border-radius:2px;
background-clip:padding-box;<避免背景溢出圓角。
}
.very-rounded{<多次實現(xiàn)圓角樣式時問題更嚴重。
-webkit-border-radius:16px;
-moz-border-radius:16px;
border-radius:16px;
background-clip:padding-box;
}
這種樣式如果只編寫一次還行,但對border-radius這樣經(jīng)常使用的屬性來說,使用純粹的CSS很快就會讓人無法忍受。但使用LESS編寫就會變得更容易,而且代碼也易于閱讀和維護。針對這種情況,我們可以編寫一個能重用的.border-radius函數(shù),把代碼改成下述代碼清單這樣。代碼清單2.3使用LESS實現(xiàn)圓角樣式
.border-radius(@value){<這是可重用的函數(shù),在LESS的俚語中,這叫“混入”。
-webkit-border-radius:@value;
-moz-border-radius:@value;
border-radius:@value;
background-clip:padding-box;
}
.slightly-rounded{
.border-radius(2px);<使用這個函數(shù),傳入半徑大小。
}
.very-rounded{
.border-radius(16px);<再次使用這個函數(shù),多次設(shè)定border-radius屬性。
}
LESS及類似的工具就是通過讓你重用CSS代碼片段的方式來提升效率。2.LESS能讓你事半功倍需要在多處使用border-radius屬性時,你便會發(fā)現(xiàn)不要什么都寫兩次(WritingEverythingTwice,簡稱WET)的好處。遵守DRY原則,每次需要實現(xiàn)圓角樣式時就不用列出所有四個屬性,只需重用.border-radius這個LESS混入即可。預處理在精益開發(fā)流程中扮演著重要的角色:要使用這個規(guī)則時不用每次都編寫所有廠商前綴,而且在一處就能修改所有前綴,讓代碼更易于維護。LESS能做的不止這些,它還能把靜態(tài)規(guī)則和設(shè)定這些規(guī)則的值清楚地分開。在CSS樣式表中經(jīng)常能看到類似下面的代碼:
a{
background-color:#FFC;
}
blockquote{
background-color:#333;
color:#FFC;
}
LESS允許我們使用變量,這樣就不用到處復制粘貼顏色代碼了。為變量起個恰當?shù)拿Q,在瀏覽樣式表時就能輕易識別使用的是什么顏色。3.使用LESS變量使用LESS可以把顏色賦值給變量,避免潛在的問題,例如在一個地方修改了顏色,但忘了修改使用這個顏色的其他地方。使用變量還能把顏色和設(shè)計中的其他可變參數(shù)統(tǒng)一放在一個地方。下述代碼展示了如何使用LESS變量:
@yellowish:#FFC;<聲明變量有助于定位和替換顏色,還能避免出現(xiàn)問題。
a{
background-color:@yellowish;<直接引用變量就能使用了。
}
blockquote{
background-color:#333;
color:@yellowish;
}
就像我在2.2節(jié)開頭提到的一樣,這樣做能讓代碼遵守DRY原則。在這里使用DRY原則特別有用,因為這樣一來,我們就不用復制粘貼顏色代碼了,因此能避免輸入錯誤導致的問題。除此之外,LESS等語言還提供了生成其他顏色的函數(shù),例如生成更深的綠色或更透明的白色等有趣的顏色算法?,F(xiàn)在我們轉(zhuǎn)變一下話題,介紹如何使用Grunt任務(wù)把LESS代碼編譯成CSS。2.2.2處理LESS本章前面說過,Grunt任務(wù)由兩個不同的部分組成——任務(wù)和配置:任務(wù)是最重要的,這是運行構(gòu)建時Grunt要執(zhí)行的代碼,一般都能找到符合需求的插件;配置是傳給grunt.initConfig方法的對象,幾乎所有Grunt任務(wù)都需要配置。在閱讀本章剩余內(nèi)容的過程中,你會看到如何配置各個任務(wù)。為了使用Grunt把LESS文件編譯成能直接伺服的CSS,我們要使用grunt-contrib-less包。還記得怎么安裝JSHint插件嗎?這個包的安裝方法與之相同,只不過是包名變了,因為我們要使用的插件變了。在終端里執(zhí)行下述命令安裝grunt-contrib-less包:
npminstallgrunt-contrib-less--save-dev
這個插件提供了一個任務(wù),名為less,在Gruntfile.js文件中加載這個任務(wù)的方式如下:
grunt.loadNpmTasks('grunt-contrib-less');
從現(xiàn)在開始,為了行文簡潔,我會省略各個示例中npminstall這一步和grunt.loadNpmTasks這部分代碼。不過你仍然要執(zhí)行npminstall獲取包,并在Gruntfile.js文件中加載插件。任何時候你都可以查看本書的配套源碼,那里有完整的代碼。設(shè)置這個構(gòu)建任務(wù)的方法很簡單:把屬性名指定為輸出文件的名稱,把對應(yīng)的值設(shè)為用來生成CSS文件的源文件的路徑。這個例子在本書配套源碼的ch02/02_less-task文件夾中。
grunt.initConfig({
less:{
compile:{
files:{
'build/css/compiled.css':'public/css/layout.less'
}
}
}
});
執(zhí)行任務(wù)的最后一步是在命令行中調(diào)用grunt。在本例中,我們需要在終端里執(zhí)行g(shù)runtless命令。我們通常建議你明確指定目標。本例中,指定目標的方式是gruntless:compile。如果不指定目標名,所有目標都會被執(zhí)行。Grunt的配置方式具有一致性在往下看之前,我要提一個在使用Grunt的過程中會讓你感到舒服的細節(jié)。不同任務(wù)之間的配置方式不會有太大差異,尤其是那些由Grunt團隊開發(fā)的任務(wù)。即便是npm中的任務(wù),只要有配置,方式也差不多。在閱讀本章的過程中你會發(fā)現(xiàn),我介紹的各個任務(wù),就算提供了大量操作方式,其配置的方式也都類似。使用Grunt執(zhí)行構(gòu)建目標less:compile,會把layout.less文件編譯成compiled.css文件。輸入文件不僅可以是單個文件,還可以是一組文件。此時,得到的是一個打包文件,包含編譯所有LESS輸入文件后得到的CSS。我們稍后就會詳細介紹打包。下述代碼清單是個示例。代碼清單2.4聲明一組輸入文件
grunt.initConfig({
less:{
compile:{
files:{
'build/css/compiled.css':[
'public/css/layout.less',
'public/css/components.less',
'public/css/views/foo.less',
'public/css/views/bar.less'
]
}
}
}
});
挨個列出每個文件不是不可以,但是如果有上百個文件,最好使用通配模式。下面就介紹這個模式。精通通配模式我們可以使用Grunt提供的通配功能,進一步改進上述代碼中的配置。通配6是一種文件路徑匹配機制,可以幫你使用文件路徑模式來包含或排除文件。這個模式特別有用,因為我們不用手動列出靜態(tài)資源文件夾中的所有文件,這樣能避免一些常見的錯誤,例如,忘記把新樣式表添加到列表中。6Grunt網(wǎng)站很好地說明了通配的用法,詳情請訪問\hhttp://bevacqua.io/bf/globbing。如果想讓構(gòu)建任務(wù)排除某些文件,例如第三方提供的文件,也用得到通配模式。下述代碼展示了一些有用的通配模式:
[
'p
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 生物標志物在藥物臨床試驗中的數(shù)據(jù)管理
- 生物材料介導的免疫微環(huán)境重塑再生策略
- 生物復方制劑組分相互作用臨床試驗設(shè)計
- 生物制劑臨床試驗中的生物標志物應(yīng)用進展
- 華為技術(shù)公司人力資源主管面試題及答案詳解
- 財經(jīng)記者崗位面試參考題集
- 生殖醫(yī)學個體化方案設(shè)計
- 生活方式干預在糖尿病管理質(zhì)量控制中的價值
- 瓣膜鈣化的早篩早診策略
- 渤海銀行財富管理顧問筆試模擬題集含答案
- 西師版新編五上數(shù)學總復習教案
- 新生兒肺臟超聲
- MOOC 創(chuàng)業(yè)管理-江蘇大學 中國大學慕課答案
- 第十一章 突發(fā)公共衛(wèi)生法律制度
- 第三章掃描電子顯微鏡【完整版】PPT
- 涉詐風險賬戶審查表
- 整形外科診療指南
- 大干圍碼頭地塊概況
- 大學生創(chuàng)新創(chuàng)業(yè)基礎(chǔ)知到章節(jié)答案智慧樹2023年齊齊哈爾大學
- 小學四年級語文上冊期末復習教案教學設(shè)計
- GB/T 8539-2000齒輪材料及熱處理質(zhì)量檢驗的一般規(guī)定
評論
0/150
提交評論