基于gulp合并壓縮Seajs模塊的方式說明
之前的項(xiàng)目一直采用grunt來構(gòu)建,然后用requirejs做模塊化,requirejs官方有提供grunt的插件來做壓縮合并?,F(xiàn)在的項(xiàng)目切到了gulp,模塊化用起了seajs,自然而然地也想到了模塊合并壓縮的問題。
然后一開始在解決這個(gè)問題的時(shí)候,并不是很順利,在npm上并沒有那種特別流行的專門用來做seajs合并壓縮的gulp插件,雖然在seajs的github上也看了不少的issue,但是大多數(shù)都是只能將所有的模塊文件合并成一個(gè)總的文件,這對(duì)于單頁(yè)面的應(yīng)用來說肯定沒有問題,但是對(duì)于多頁(yè)面的應(yīng)用而言,顯然就違背了模塊化思想中按需加載的核心,所以我想要的是一個(gè)能夠根據(jù)我每個(gè)頁(yè)面各自所依賴的模塊來按需合并的方法。
這個(gè)按需合并的意思,一方面是只合并一個(gè)頁(yè)面所依賴的那些模塊,另一方面是,還能過濾掉某些模塊不參與合并,考慮這個(gè)的原因在于有些模塊,比如jquery等,都屬于第三方依賴的庫(kù),可能文件比較大,最重要的是你幾乎不會(huì)去改動(dòng)它的代碼,所以這些模塊不合并到頁(yè)面的js中,會(huì)有助于更好地利用瀏覽器緩存。本文介紹一個(gè)簡(jiǎn)單可行的辦法,來做基于gulp構(gòu)建的中小型項(xiàng)目中的seajs合并壓縮。
注:為了說明,seajs合并后的效果,本文提供了一個(gè)演示demo,它有兩個(gè)頁(yè)面:login.html和regist.html,分別用來模擬多頁(yè)應(yīng)用中的兩個(gè)獨(dú)立的文件,可通過以下鏈接來查看:
http://liuyunzhuge.github.io/blog/seajs/dist/html/login.html
http://liuyunzhuge.github.io/blog/seajs/dist/html/regist.html
以login.html為例,查看這個(gè)頁(yè)面的源文件中,會(huì)看到它除了引用seajs以及相關(guān)的配置文件common.js外,只引用了app/login作為頁(yè)面的main js,這個(gè)app/login模塊其實(shí)對(duì)應(yīng)的就是js/app/login.js:
但實(shí)際上,這個(gè)login.js依賴了更多的模塊js,你可以通過chrome的soures來查看該頁(yè)面加載的詳細(xì)js資源:
在login.js合并之前,它的代碼是這樣的:
但是在前2個(gè)截圖中,我們并沒有看到mod/mod1.js , mod/mod2.js , deps/fastclick.js這三個(gè)文件,我們除了看到login.js,還看到了lib/bootstrap.js , lib/jquery.js , lib/jquery.validate.js。這就是合并的效果。一方面保持了js/lib文件夾下的模塊都不會(huì)參與合并,另一方面保證了頁(yè)面的main js所依賴的其它模塊,都合并到頁(yè)面的main js文件中來。
該demo相關(guān)的代碼可通過以下鏈接進(jìn)行查看:
https://github.com/liuyunzhuge/blog/tree/master/seajs
1. 合并思路
其實(shí)方法還算比較簡(jiǎn)單,我最后再介紹。
1)我先說下自己對(duì)seajs的模塊進(jìn)行組織的一種文件夾結(jié)構(gòu),它是這樣的:
這個(gè)結(jié)構(gòu)借鑒于requirejs,盡量讓文件組織扁平化,對(duì)于中小型前端項(xiàng)目來說,應(yīng)該不會(huì)太麻煩。其中各個(gè)文件夾的作用是:
1)js/app 存放各個(gè)頁(yè)面的main js,基本上是一個(gè)頁(yè)面一個(gè)js的邏輯
2)js/deps 存放哪些需要被合并到main js的第三方模塊
3)js/lib 存放哪些不需要參與合并的第三方模塊
4)js/mod 存放各個(gè)項(xiàng)目中自己寫的一些js模塊
5)common.js 是seajs的配置文件。
2)在common.js中把js/lib下的模塊都配置到了alias選項(xiàng)里面,因?yàn)檫@些js都不參與合并,需要使用到瀏覽器緩存,alias可以方便我們?cè)谛薷幕蛏?jí)了js/lib下的文件的時(shí)候,對(duì)這些文件的加載地址做一點(diǎn)更新:
base配置到了js文件夾。在模塊開發(fā)中,要require其他模塊時(shí),我的習(xí)慣都是直接寫mod/mod1這樣的模塊標(biāo)識(shí),不用相對(duì)標(biāo)識(shí),即使要定義的這個(gè)模塊所依賴的模塊跟它存在于同一個(gè)文件夾中,這也是我為啥把base目錄設(shè)置到j(luò)s文件夾的原因,有點(diǎn)類似站點(diǎn)根目錄的感覺。
3)合并的思路:主要是利用gulp-seajs-transport和gulp-seajs-concat這兩個(gè)gulp插件。雖然它們?cè)趃ithub上不是很熱門,但是已經(jīng)很好地解決我的問題了,使用起來也非常簡(jiǎn)單:
(更多內(nèi)容需要查看本文開始處提供的源碼鏈接,找到相關(guān)的gulpfile.js文件)
gulp-seajs-transport可以幫助你把seajs的模塊文件從匿名模塊,變成具名模塊。比如js/mod/mod1.js在構(gòu)建前是這樣的:
但是經(jīng)過transport處理后就會(huì)變成:
這個(gè)是seajs合并工作中比較關(guān)鍵的一點(diǎn),它不像requirejs,直接做concat即可;它必須先經(jīng)過一個(gè)transport的任務(wù)處理,將匿名模塊變成具名模塊,同時(shí)用define的第二個(gè)參數(shù)來描述這個(gè)模塊的所有依賴,就像requirejs那樣。只有做完了transport,才能利用gulp-seajs-concat做合并。原因請(qǐng)參考:https://github.com/seajs/seajs/issues/426。
gulp-seajs-concat做合并的時(shí)候,就很簡(jiǎn)單了,只要告訴它一個(gè)base選項(xiàng)即可,這個(gè)base選項(xiàng)跟js/common.js中base選項(xiàng)保持一致。因?yàn)間ulp-seajs-concat根據(jù)base和transport之后的模塊,就能找到它所依賴的其它模塊文件。
4)頁(yè)面中使用main js時(shí)要采用這種方式:
use的參數(shù)名稱,必須跟合并之后的main js的主模塊ID保持一致。比如js/app/login.js合并之后是這個(gè)樣子:
第一個(gè)define對(duì)應(yīng)的模塊就是合并后文件內(nèi)的主模塊,紅框的內(nèi)容就是該主模塊的id,seajs use這個(gè)模塊的時(shí)候,參數(shù)名稱必須和這個(gè)id一致。否則seajs即使成功的加載到了這個(gè)文件,也不會(huì)執(zhí)行任何模塊內(nèi)的代碼。因?yàn)閟eajs有一個(gè)規(guī)則:ID 和路徑匹配原則,其中有點(diǎn)跟這個(gè)相關(guān),就是:當(dāng)seajs use到一個(gè)文件內(nèi)包含多個(gè)模塊時(shí),會(huì)根據(jù)use的參數(shù)名來尋找這個(gè)文件內(nèi)的主模塊,只有它們完全匹配,才能找得到。
5)壓縮混淆:使用gulp-uglify:
但是要注意那個(gè)mangle,必須把require exports module排除掉,否則會(huì)引發(fā)一些意外的問題。
2. 本文小結(jié)
本文內(nèi)容雖然很簡(jiǎn)單,但是在剛切到gulp和seajs的時(shí)候,還是費(fèi)了不少時(shí)間才把本文的問題解決,雖然在準(zhǔn)備demo的時(shí)候進(jìn)展地比我當(dāng)時(shí)的情況要順利的多…不管怎么樣,希望本文的內(nèi)容多多少少能幫助到一些朋友。
相關(guān)文章
vue2.0實(shí)戰(zhàn)之基礎(chǔ)入門(1)
這篇文章主要為大家詳細(xì)介紹了vue2.0實(shí)戰(zhàn)第一篇基礎(chǔ)入門的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03通過修改360搶票的刷新頻率和突破8車次限制實(shí)現(xiàn)方法
這篇文章主要介紹了通過修改360搶票的刷新頻率和突破8車次限制實(shí)現(xiàn)方法的相關(guān)資料,現(xiàn)在刷票工具很多,這里就舉一例修改,增加搶票頻率及突破8車次限制,需要的朋友可以參考下2017-01-01js中合并對(duì)象的幾種實(shí)現(xiàn)方法
"js 合并對(duì)象"是一種在JavaScript編程中常見的操作,用于將多個(gè)對(duì)象的屬性合并到一起,通常,我們會(huì)使用ES6的擴(kuò)展運(yùn)算符或者Object.assign()函數(shù)來實(shí)現(xiàn)這個(gè)功能,感興趣的可以了解一下2023-08-08JavaScript去除空格的三種方法(正則/傳參函數(shù)/trim)
個(gè)人認(rèn)為去除空格最好的方法.采用的是正則表達(dá)式,這是最核心的原理,同時(shí)呢,還是有其他方法可以辦到的,接下來將介紹一下三種方法(trim)空格,感興趣的朋友可以了解下,或許對(duì)你有幫助呢2013-02-02JS判斷字符串變量是否含有某個(gè)字串的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄狫S判斷字符串變量是否含有某個(gè)字串的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06js獲取checkbox復(fù)選框選中的選項(xiàng)實(shí)例
這篇文章主要介紹了js如何獲取checkbox復(fù)選框選中的選項(xiàng),比較適合新手,需要的朋友可以參考下2014-08-08TypeScript中type和interface的區(qū)別及注意事項(xiàng)
type的類型別用可以用戶其他的類型,比如聯(lián)合類型、元祖類型、基本類型,interface不行,下面這篇文章主要給大家介紹了關(guān)于TypeScript中type和interface的區(qū)別及注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下2022-10-10