在JavaScript模塊化和閉包和JavaScript-Module-Pattern-In-Depth這兩篇文章中,提到了模塊化的基本思想,但是在實(shí)際項(xiàng)目中我們還需要考慮哪些問題呢。知道問題在哪里,google大法就可以上場(chǎng)了。
前端工程的問題
JavaScript的模塊化
流行的模塊化解決方案現(xiàn)在有很多,主要分為以下兩種規(guī)范
- AMD:AMD 規(guī)范是JavaScript開發(fā)的一次重要嘗試,它以簡單而優(yōu)雅的方式統(tǒng)一了JavaScript的模塊定義和加載機(jī)制,并迅速得到很多框架的認(rèn)可和采納。這對(duì)開發(fā)人員來說是一個(gè)好消息,通過AMD我們降低了學(xué)習(xí)和使用各種框架的門檻,能夠以一種統(tǒng)一的方式去定義和使用模塊,提高開發(fā)效率,降低了應(yīng)用維護(hù)成本。
- CommonJS:node.js的方式,在前端需要打包工具配合使用。在后端比較好用。
我們站在開發(fā)的角度,當(dāng)然希望一種規(guī)范打天下,但是現(xiàn)實(shí)情況往往復(fù)雜,需要不同的解決方法,這時(shí)候我們一般會(huì)增加層次,進(jìn)行包裝,比如在前端可以用node規(guī)范,用構(gòu)建工具進(jìn)行打包。
JavaScript的模塊化需要解決下面幾個(gè)問題
- 定義模塊
- 管理模塊依賴
- 加載模塊
- 打包
- 包管理
CSS的模塊化
- sass
- less
- 其他
CSS的模塊化要解決CSS語法的一些問題:
- 沒有變量
- 沒有函數(shù)
- 不能嵌套等
- 文件不能互相引用
HTML的模塊化
后端模版,前端模版和各種webapp框架都可以提供這種能力
- Jade:node.js的后端模版,基本上每個(gè)web框架都有一個(gè)默認(rèn)的后端模版引擎
- ember.js:因?yàn)榍岸耸褂胔andlebars,所以有好感,不重復(fù)造輪子才是好人
- angular.js:不推薦使用,學(xué)習(xí)曲線比較陡峭,大部分概念在前端不適用,實(shí)際上把面向?qū)ο蠛秃芏嘣O(shè)計(jì)模式拿到前端,屬于探索性質(zhì),沒有太多實(shí)際意義。
- backbone.js & marionette.js:我比較喜歡,因?yàn)楹唵慰煽?,backbone本身并不提供MVC中V的能力,可以考慮marionette
- react.js:現(xiàn)在很火,一直沒機(jī)會(huì)實(shí)踐
- handlebars.js:這個(gè)比較好,就是一個(gè)模版引擎,前后端都可以用,可以配合backbone和ember使用
當(dāng)然,webapp的框架一般都提供了js的模塊化管理能力,這里主要看中她們對(duì)html的模塊化設(shè)計(jì)。
HTML模塊化要解決:
- 數(shù)據(jù)綁定
- 定義界面組件
- 組裝界面組件
- 輸出渲染界面組件
- 性能的優(yōu)化
組件化
解決了模塊化問題以后,我們需要把頁面按照功能分離出來,組成一個(gè)個(gè)模塊,這樣復(fù)合面相對(duì)象和分治的思想,也方便復(fù)用。
- 組件化:開發(fā)的時(shí)候分好功能模塊
- 組件倉庫:獨(dú)立出模塊,放到組件倉庫,比如npm
開發(fā)
- 文件監(jiān)聽: 文件改動(dòng)時(shí)自動(dòng)編譯
- 頁面自動(dòng)刷新:基于文件監(jiān)聽功能,當(dāng)代碼改動(dòng)的時(shí)候,自動(dòng)刷新瀏覽器
- 調(diào)試插件:ember等webapp框架都有自己的瀏覽器調(diào)試插件
- 開發(fā)腳手架:rails的流行可能和方便的cli腳手架關(guān)系密切哦,打一個(gè)命令mvc都相應(yīng)的在合適的文件夾下出現(xiàn)。
- 合理的目錄結(jié)構(gòu):
- 按組件劃分文件
- 支持多個(gè)應(yīng)用
- 資源定位:資源定位能力,可以有效的分離開發(fā)路徑與部署路徑之間的關(guān)系,工程師不再關(guān)心資源部署到線上之后去了哪里,變成了什么名字,這些都可以通過配置來指定。而工程師只需要使用相對(duì)路徑來定位自己的開發(fā)資源即可。這樣的好處是 資源可以發(fā)布到任何靜態(tài)資源服務(wù)器的任何路徑上而不用擔(dān)心線上運(yùn)行時(shí)找不到它們,而且代碼 具有很強(qiáng)的可移植性,甚至可以從一個(gè)產(chǎn)品線移植到另一個(gè)產(chǎn)品線而不用擔(dān)心線上部署不一致的問題。
- 內(nèi)容嵌入:內(nèi)容嵌入可以為工程師提供諸如圖片base64嵌入到css、js里,前端模板編譯到j(luò)s文件中,將js、css、html拆分成幾個(gè)文件最后合并到一起的能力。有了這項(xiàng)能力,可以有效的減少http請(qǐng)求數(shù),提升工程的可維護(hù)性。
- 依賴聲明:按需加載資源
打包構(gòu)建
模塊化可以解決開發(fā)中代碼管理,團(tuán)隊(duì)分工的各種問題,讓小組成員集中精力完成自己的模塊并復(fù)用模塊。當(dāng)我們的項(xiàng)目完成后,接下來的問題就是打包。
打包這里面有個(gè)核心問題就是靜態(tài)資源合并和如何讓瀏覽器加載頁面更快速。
- 為了快速,不能過多的請(qǐng)求文件(合并請(qǐng)求)
- 為了快速,請(qǐng)求文件越小越好(按需請(qǐng)求)
- 為了快速,命中緩存的次數(shù)越多越好(瀏覽器緩存,CDN緩存,服務(wù)器緩存)
現(xiàn)在最流行的是基于task的任務(wù)管理工具,核心任務(wù)之一就是打包嘍:
- grunt
- gulp
- webpack:模塊加載和打包功能(非taskbase)
打包需要解決以下問題:
- javascript最小化,合并,驗(yàn)證
- css最小化,合并
- html模版的編譯
- 靜態(tài)資源的管理
- 靜態(tài)資源的版本,比如加時(shí)間戳或者md5后綴
- 圖片base64嵌入
- 資源的引用
- 解耦開發(fā)規(guī)范和部署規(guī)范:開發(fā)目錄和部署目錄可以配置,不依賴相對(duì)路徑
持續(xù)集成
- 挑選一個(gè)喜歡的前端測(cè)試框架。
- 提交代碼后自動(dòng)跑測(cè)試腳本。
- 及時(shí)反饋給提交代碼的人,是否提交有問題(多人合作的時(shí)候比較重要)。
但是測(cè)試一般用在對(duì)接口輸入輸出做白盒測(cè)試,自動(dòng)測(cè)試界面的monkey測(cè)試或者更高級(jí)的模擬人點(diǎn)擊的測(cè)試方法也可以在這個(gè)階段嘗試自動(dòng)化(monkey測(cè)試就是計(jì)算機(jī)腳本模擬人的點(diǎn)擊行為,胡亂點(diǎn)擊測(cè)試,)。功能性的測(cè)試還是人去測(cè)試比較好,這邊的CI目標(biāo)主要是提前發(fā)現(xiàn)代碼有沒有不符合規(guī)范,或者build失敗等比較初級(jí)的任務(wù),如果很要寫復(fù)雜的測(cè)試用例,開發(fā)起來不比做一個(gè)功能簡單,浪費(fèi)開發(fā)大量精力,一般只有很大的公司才有資源做吧。
給大家推薦一個(gè)很好用的工具組合,jira+git+gerrit+jenkins。jira用來項(xiàng)目管理,git用來代碼版本管理,gerrit用來review代碼,jenkins用來跑測(cè)試,對(duì)java,JavaScript等語言也可以檢查代碼錯(cuò)誤和風(fēng)格,讓開發(fā)人員提交的代碼更符合規(guī)范。
發(fā)布
打包好了以后,需要發(fā)布,發(fā)布也有幾個(gè)問題:
- 不同版本如何管理
- 靜態(tài)資源的發(fā)布問題:如CDN如何更新
- 增量更新問題
- 線上性能問題(這個(gè)不是發(fā)布可以做的事情,主要是發(fā)布后需要考慮,所以放在這里了):
- 請(qǐng)求合并
- 按需加載
運(yùn)行監(jiān)控
當(dāng)我們的服務(wù)運(yùn)行以后,需要監(jiān)控web server的運(yùn)行狀態(tài),服務(wù)器的運(yùn)行狀態(tài),設(shè)置報(bào)警機(jī)制,現(xiàn)在的云服務(wù)提供上一般都有服務(wù)器運(yùn)行情況,惡意攻擊的報(bào)警,我們?cè)谶x擇的時(shí)候注意提供商提供的這類服務(wù)也是很有必要的。
上面只是一個(gè)大綱,姑且先把問題總結(jié)出來,歡迎大家來補(bǔ)充。
但是為啥簡單的編寫頁面變得這么多問題呢?我想這和web技術(shù)在不斷快速發(fā)展有關(guān),目前還沒有一個(gè)非常成熟的整體解決方案出來。web比傳統(tǒng)的PC客戶端程序復(fù)雜,瀏覽器是一個(gè)通用的客戶端,所展示的頁面都是從服務(wù)器獲取的,這里就有網(wǎng)絡(luò)延遲的問題,瀏覽器解析性能問題等等。想到以前曾經(jīng)寫過的windows客戶端程序,在微軟的集成開發(fā)環(huán)境visual studio中,拖拖拽拽就開發(fā)好了項(xiàng)目,資源管理也有比較成熟的方案,使用的開發(fā)語言也是C++,C#這種支持模塊化,面向?qū)ο蟮恼Z言,頓時(shí)感覺前端開發(fā)在工程管理上的復(fù)雜性了。
好了,現(xiàn)在我們?nèi)绾谓鉀Q這些問題呢?
前端工程解決方案
很確信ruby on rails可以解決上面所有問題,給大家推薦一個(gè)學(xué)習(xí)ruby和rails的好地方:learnruby,需要vpn。。。這里我們手動(dòng)打造一套解決方案,有些方案需要后端支持,比如后端模版和一些性能優(yōu)化方法。
在《JavaScript模塊化-require.js,r.js和打包發(fā)布》這篇文章中,我們看到require.js,r.js,grunt配合使用來打包和發(fā)布的一個(gè)過程,可以說已經(jīng)適合小型網(wǎng)站的使用了,但是我們一一對(duì)應(yīng)上面要解決的問題,看看是否能夠滿足我們的需求。
|需求|老方案是否可以滿足|備注|
|---|---|
|js模塊化|可以|require.js可以滿足|
|css模塊化|可以|grunt,gulp可以用來執(zhí)行編譯sass,less的任務(wù)|
|HTML模塊話|可以|使用webapp框架或者模版技術(shù)|
|組件化|可以|劃分好目錄和打包規(guī)則,代碼編寫需要模塊話|
|組件倉庫|沒有涉及|老方案并沒有考慮建立npm這種組件倉庫|
|文件監(jiān)聽|可以|grunt,gulp可以做到|
|頁面自動(dòng)刷新|可以|grunt,gulp可以做到|
|開發(fā)腳手架|沒有考慮|老方案并沒有|
|合理的目錄結(jié)構(gòu)|沒有考慮|老方案希望開發(fā)人員自己定義目錄結(jié)構(gòu)|
|資源定位|不可以|老方案需要讓開發(fā)規(guī)范和發(fā)布規(guī)范一致,依賴相對(duì)路徑|
|內(nèi)容嵌入|不可以|老方案沒有考慮這個(gè)問題,需要使用url,請(qǐng)求次數(shù)比較多,或者只能手動(dòng)嵌入,比如base64的圖片|
|依賴聲明|可以|require.js配合插件text可以管理各種資源的依賴,并按需加載|
|合并文件|可以||
|最小化文件|可以|grunt,gulp任務(wù)的最常見的一種|
|模版的編譯|可以||
|緩存管理|沒有|打包后緩存的命中會(huì)下降|
|文件的版本|沒有|導(dǎo)致發(fā)布是覆蓋模式,緩存容易失效|
|圖片的合并嵌入|可以|比如制作css sprite|
|開發(fā)目錄和部署目錄解耦|沒有仔細(xì)考慮|只能通過相對(duì)路徑,而相對(duì)路徑之間的關(guān)系不能改變|
|CI|可以|可以設(shè)置自動(dòng)化任務(wù)跑測(cè)試|
|配置CDN|沒有考慮||
|增量更新|可以|rsync工具|
|請(qǐng)求合并|沒有仔細(xì)考慮|只是把文件合并在一起,并不支持同時(shí)返回多個(gè)文件,需要服務(wù)器支持|
|按需加載|沒有仔細(xì)考慮|如果合并了文件,就不能按需加載;如果按需加載,就會(huì)導(dǎo)致請(qǐng)求數(shù)目的增加,解決這個(gè)問題需要提前知道依賴的文件的列表,利用請(qǐng)求合并的技術(shù)去一次性加載|
我們提出了問題,剩下的就是解決問題了,既然上一篇文章太簡單了,我們需要一個(gè)復(fù)雜點(diǎn)的例子來看看一個(gè)中等規(guī)模的前端項(xiàng)目,應(yīng)該如何的展開。請(qǐng)看下一篇文章吧。