目錄
上周寫(xiě)了一篇?文章?介紹前端集成解決方案的基本理論,很多同學(xué)看過(guò)之后大呼不過(guò)癮。
干貨?
fuck things?在哪里!
本打算繼續(xù)完善理論鏈,形成前端工程的知識(shí)結(jié)構(gòu)。但鑒于如今的快餐文化,po主決定還是先寫(xiě)一篇實(shí)戰(zhàn)介紹,讓大家看到前端工程體系能為團(tuán)隊(duì)帶來(lái)哪些好處,調(diào)起大家的胃口再說(shuō)。
ps: 寫(xiě)完才發(fā)現(xiàn)這篇文章真的非常非常長(zhǎng),涵蓋了前端開(kāi)發(fā)中的很多方面,希望大家能有耐心看完,相信一定會(huì)有所斬獲。。。
新到松鼠團(tuán)隊(duì)的第二天,小伙伴?@nino?找到我說(shuō)
nino: 視頻項(xiàng)目打算重新梳理一下,希望能引入新的技術(shù)體系,解決現(xiàn)有的一些問(wèn)題。
po主不禁暗喜,好機(jī)會(huì),這是我專(zhuān)業(yè)啊,藍(lán)翔技校-前端集成解決方案學(xué)院-自動(dòng)化系-打包學(xué)專(zhuān)業(yè)的文憑不是白給的,于是自信滿(mǎn)滿(mǎn)的對(duì)nino說(shuō),有什么需求盡管提!
nino: 我的需求并不多,就這么幾條~~
我倒吸一口涼氣,但表面故作鎮(zhèn)定的說(shuō):恩,確實(shí)不多,讓我們先來(lái)看看第一個(gè)需求。。。
還沒(méi)等我說(shuō)完,nino打斷我說(shuō)
nino: 橋豆麻袋(稍等),還有一個(gè)最重要的需求!
松鼠公司的松鼠瀏覽器你知道吧,恩,它有很多個(gè)版本的樣子。
我希望代碼發(fā)布后能按照版本部署,不要彼此覆蓋。
舉個(gè)例子,代碼部署結(jié)構(gòu)可能是這樣的:
release/
- public/
- 項(xiàng)目名
- 1.0.0/
- 1.0.1/
- 1.0.2/
- 1.0.2-alpha/
- 1.0.2-beta/
讓歷史瀏覽器瀏覽歷史版本,沒(méi)事還能做個(gè)灰度發(fā)布,ABTest啥的,多好!
此外,我們將來(lái)會(huì)有多個(gè)項(xiàng)目使用這套開(kāi)發(fā)模式,希望能共用一些組件或者模
塊,產(chǎn)品也會(huì)公布一些api模塊給第三方使用,所以共享模塊功能也要加上。
總的來(lái)說(shuō),還要追加兩個(gè)部署需求:
nino: 怎么樣,不算復(fù)雜吧,這個(gè)項(xiàng)目很趕,
3天
搞定怎么樣?
我凝望著會(huì)議室白板上的這些需求,正打算爭(zhēng)辯什么,一扭頭發(fā)現(xiàn)nino已經(jīng)不見(jiàn)了。。。正在沮喪之際,小伙伴?@hinc?過(guò)來(lái)找我,跟他大概講了一下nino的需求,正想跟他抱怨工期問(wèn)題時(shí),hinc卻說(shuō)
hinc: 恩,這正是我們需要的開(kāi)發(fā)體系,不過(guò)我這里還有一個(gè)需求。。。
3天時(shí)間,13項(xiàng)前端技術(shù)元素,靠譜么。。。
一覺(jué)醒來(lái),輕松了許多,但還有任務(wù)在身,不敢有半點(diǎn)怠慢。整理一下昨天的需求,我們來(lái)做一個(gè)簡(jiǎn)單的劃分。
這樣一套規(guī)范、框架、工具和倉(cāng)庫(kù)的開(kāi)發(fā)體系,服從我之前介紹的?前端集成解決方案?的描述。前端界每天都團(tuán)隊(duì)在設(shè)計(jì)和實(shí)現(xiàn)這類(lèi)系統(tǒng),它們其實(shí)是有規(guī)律可循的。百度出品的?fis?就是一個(gè)能幫助快速搭建前端集成解決方案的工具。使用fis我應(yīng)該可以在3天之內(nèi)完成這些任務(wù)。
ps: 這不是一篇關(guān)于fis的軟文,如果這樣的一套系統(tǒng)基于grunt實(shí)現(xiàn)相信會(huì)有非常大量的開(kāi)發(fā)工作,3天完成幾乎是不可能的任務(wù)。
不幸的是,現(xiàn)在fis官網(wǎng)所介紹的?并不是?fis,而是一個(gè)叫?fis-plus?的項(xiàng)目,該項(xiàng)目并不像字面理解的那樣是fis的加強(qiáng)版,而是在fis的基礎(chǔ)上定制的一套面向百度前端團(tuán)隊(duì)的解決方案,以php為后端語(yǔ)言,跟smarty有較強(qiáng)的綁定關(guān)系,有著?19項(xiàng)
?技術(shù)要素,密切配合百度現(xiàn)行技術(shù)選型。絕大多數(shù)非百度前端團(tuán)隊(duì)都很難完整接受這19項(xiàng)技術(shù)選型,尤其是其中的部署、框架規(guī)范,跟百度前端團(tuán)隊(duì)相關(guān)開(kāi)發(fā)規(guī)范、部署規(guī)范、以及php、smarty等有著較深的綁定關(guān)系。
因此如果你的團(tuán)隊(duì)用的不是?php后端
?&&?smarty模板
?&&?modjs模塊化框架
?&&?bingo框架
?的話(huà),請(qǐng)查看?fis的文檔,或許不會(huì)有那么多困惑。
ps: fis是一個(gè)構(gòu)建系統(tǒng)內(nèi)核,很好的抽象了前端集成解決方案所需的通用工具需求,本身不與任何后端語(yǔ)言綁定。而基于fis實(shí)現(xiàn)的具體解決方案就會(huì)有具體的規(guī)范和技術(shù)選型了。
言歸正傳,讓我們基于?fis?開(kāi)始實(shí)踐這套開(kāi)發(fā)體系吧!
前端開(kāi)發(fā)體系設(shè)計(jì)第一步要定義開(kāi)發(fā)概念。開(kāi)發(fā)概念是指針對(duì)開(kāi)發(fā)資源的分類(lèi)概念。開(kāi)發(fā)概念的確立,直接影響到規(guī)范的定制。比如,傳統(tǒng)的開(kāi)發(fā)概念一般是按照文件類(lèi)型劃分的,所以傳統(tǒng)前端項(xiàng)目會(huì)有這樣的目錄結(jié)構(gòu):
這樣確實(shí)很直接,任何智力健全的人都知道每個(gè)文件該放在哪里。但是這樣的開(kāi)發(fā)概念劃分將給項(xiàng)目帶來(lái)較高的維護(hù)成本,并為項(xiàng)目臃腫埋下了工程隱患,理由是:
ps: 除非你的團(tuán)隊(duì)只有1-2個(gè)人,你的項(xiàng)目只有很少的代碼量,而且不用關(guān)心性能和未來(lái)的維護(hù)問(wèn)題,否則,以文件為依據(jù)設(shè)計(jì)的開(kāi)發(fā)概念是應(yīng)該被拋棄的。
以我個(gè)人的經(jīng)驗(yàn),更傾向于具有一定語(yǔ)義的開(kāi)發(fā)概念。綜合前面的需求,我為這個(gè)開(kāi)發(fā)體系確定了3個(gè)開(kāi)發(fā)資源概念:
ps: 開(kāi)發(fā)概念越簡(jiǎn)單越好,前面提到的fis-plus也有類(lèi)似的開(kāi)發(fā)概念,有組件或模塊(widget),頁(yè)面(page),測(cè)試數(shù)據(jù)(test),非模塊化靜態(tài)資源(static)。有的團(tuán)隊(duì)在模塊之中又劃分出api模塊和ui模塊(組件)兩種概念。
基于開(kāi)發(fā)概念的確立,接下來(lái)就要確定目錄規(guī)范了。我通常會(huì)給每種開(kāi)發(fā)資源的目錄取一個(gè)有語(yǔ)義的名字,三種資源我們可以按照概念直接定義目錄結(jié)構(gòu)為:
project
- modules 存放模塊化資源
- pages 存放頁(yè)面資源
- static 存放非模塊化資源
這樣劃分目錄確實(shí)直觀(guān),但結(jié)合前面hinc說(shuō)過(guò)的,希望能使用component倉(cāng)庫(kù)資源,因此我決定將模塊化資源目錄命名為components
,得到:
project
- components 存放模塊化資源
- pages 存放頁(yè)面資源
- static 存放非模塊化資源
而nino又提到過(guò)模塊資源分為項(xiàng)目模塊和公共模塊,以及hinc提到過(guò)希望能從component安裝一些公共組件到項(xiàng)目中,因此,一個(gè)components目錄還不夠,想到nodejs用node_modules作為模塊安裝目錄,因此我在規(guī)范中又追加了一個(gè)?component_modules
?目錄,得到:
project
- component_modules 存放外部模塊資源
- components 存放項(xiàng)目模塊資源
- pages 存放頁(yè)面資源
- static 存放非模塊化資源
nino說(shuō)過(guò)今后大多數(shù)項(xiàng)目采用nodejs作為后端,express是比較常用的nodejs的server框架,express項(xiàng)目通常會(huì)把后端模板放到?views
?目錄下,把靜態(tài)資源放到?public
?下。為了迎合這樣的需求,我將page、static兩個(gè)目錄調(diào)整為?views
?和?public
,規(guī)范又修改為:
project
- component_modules 存放外部模塊資源
- components 存放項(xiàng)目模塊資源
- views 存放頁(yè)面資源
- public 存放非模塊化資源
考慮到頁(yè)面也是一種靜態(tài)資源,而public
這個(gè)名字不具有語(yǔ)義性,與其他目錄都有概念沖突,不如將其與views
目錄合并,views目錄負(fù)責(zé)存放頁(yè)面和非模塊化資源比較合適,因此最終得到的開(kāi)發(fā)目錄結(jié)構(gòu)為:
project
- component_modules 存放外部模塊資源
- components 存放項(xiàng)目模塊資源
- views 存放頁(yè)面以及非模塊化資源
托nino的福,咱們的部署策略將會(huì)非常復(fù)雜,根據(jù)要求,一個(gè)完整的部署結(jié)果應(yīng)該是這樣的目錄結(jié)構(gòu):
release
- public
- 項(xiàng)目名
- 1.0.0 1.0.0版本的靜態(tài)資源都構(gòu)建到這里
- 1.0.1 1.0.1版本的靜態(tài)資源都構(gòu)建到這里
- 1.0.2 1.0.2版本的靜態(tài)資源都構(gòu)建到這里
...
- views
- 項(xiàng)目名
- 1.0.0 1.0.0版本的后端模板都構(gòu)建到這里
- 1.0.1 1.0.1版本的后端模板都構(gòu)建到這里
- 1.0.2 1.0.2版本的后端模板都構(gòu)建到這里
...
由于還要部署一些可以被第三方使用的模塊,public下只有項(xiàng)目名的部署還不夠,應(yīng)改把模塊化文件單獨(dú)發(fā)布出來(lái),得到這樣的部署結(jié)構(gòu):
release
- public
- component_modules 模塊化資源都部署到這個(gè)目錄下
- module_a
- 1.0.0
- module_a.js
- module_a.css
- module_a.png
- 1.0.1
- 1.0.2
...
- 項(xiàng)目名
- 1.0.0 1.0.0版本的靜態(tài)資源都構(gòu)建到這里
- 1.0.1 1.0.1版本的靜態(tài)資源都構(gòu)建到這里
- 1.0.2 1.0.2版本的靜態(tài)資源都構(gòu)建到這里
...
- views
- 項(xiàng)目名
- 1.0.0 1.0.0版本的后端模板都構(gòu)建到這里
- 1.0.1 1.0.1版本的后端模板都構(gòu)建到這里
- 1.0.2 1.0.2版本的后端模板都構(gòu)建到這里
...
由于?component_modules
?這個(gè)名字太長(zhǎng)了,如果部署到這樣的路徑下,url會(huì)很長(zhǎng),這也是一個(gè)優(yōu)化點(diǎn),因此最終決定部署結(jié)構(gòu)為:
release
- public
- c 模塊化資源都部署到這個(gè)目錄下
- 公共模塊
- 版本號(hào)
- 項(xiàng)目名
- 版本號(hào)
- 項(xiàng)目名
- 版本號(hào) 非模塊化資源都部署到這個(gè)目錄下
- views
- 項(xiàng)目名
- 版本號(hào) 后端模板都構(gòu)建到這個(gè)目錄下
插一句,并不是所有團(tuán)隊(duì)都會(huì)有這么復(fù)雜的部署要求,這和松鼠團(tuán)隊(duì)的業(yè)務(wù)需求有關(guān),但我相信這個(gè)例子也不會(huì)是最復(fù)雜的。每個(gè)團(tuán)隊(duì)都會(huì)有自己的運(yùn)維需求,前端資源部署經(jīng)常牽連到公司技術(shù)架構(gòu),因此很多前端項(xiàng)目的開(kāi)發(fā)目錄結(jié)構(gòu)會(huì)和部署要求保持一致。這也為項(xiàng)目間模塊的復(fù)用帶來(lái)了成本,因?yàn)榇a中寫(xiě)的url通常是部署后的路徑,遷移之后就可能失效了。
解耦開(kāi)發(fā)規(guī)范和部署規(guī)范是前端開(kāi)發(fā)體系的設(shè)計(jì)重點(diǎn)。
好了,去吃個(gè)午飯,下午繼續(xù)。。。
我準(zhǔn)備了一個(gè)樣例項(xiàng)目:
project
- views
- logo.png
- index.html
- fis-conf.js
- README.md
fis-conf.js
是fis工具的配置文件,接下來(lái)我們就要在這里進(jìn)行構(gòu)建配置了。雖然開(kāi)發(fā)規(guī)范和部署規(guī)范十分復(fù)雜,但好在fis有一個(gè)非常強(qiáng)大的?roadmap.path?功能,專(zhuān)門(mén)用于分類(lèi)文件、調(diào)整發(fā)布結(jié)構(gòu)、指定文件的各種屬性等功能實(shí)現(xiàn)。
所謂構(gòu)建,其核心任務(wù)就是將文件按照某種規(guī)則進(jìn)行分類(lèi)(以文件后綴分類(lèi),以模塊化/非模塊化分類(lèi),以前端/后端代碼分類(lèi)),然后針對(duì)不同的文件做不同的構(gòu)建處理。
閑話(huà)少說(shuō),我們先來(lái)看一下基本的配置,在?fis-conf.js
?中添加代碼:
fis.config.set('roadmap.path', [
{
reg : '**.md', //所有md后綴的文件
release : false //不發(fā)布
}
]);
以上配置,使得項(xiàng)目中的所有md后綴文件都不會(huì)發(fā)布出來(lái)。release是定義file對(duì)象發(fā)布路徑的屬性,如果file對(duì)象的release屬性為false,那么在項(xiàng)目發(fā)布階段就不會(huì)被輸出出來(lái)。
在fis中,roadmap.pah是一個(gè)數(shù)組數(shù)據(jù),數(shù)組每個(gè)元素是一個(gè)對(duì)象,必須定義?reg
?屬性,用以匹配項(xiàng)目文件路徑從而進(jìn)行分類(lèi)劃分,reg屬性的取值可以是路徑通配字符串或者正則表達(dá)式。fis有一個(gè)內(nèi)部的文件系統(tǒng),會(huì)給每個(gè)源碼文件創(chuàng)建一個(gè)?fis.File?對(duì)象,創(chuàng)建File對(duì)象時(shí),按照roadmap.path的配置逐個(gè)匹配文件路徑,匹配成功則把除reg之外的其他屬性賦給File對(duì)象,fis中各種處理環(huán)節(jié)及插件都會(huì)讀取所需的文件對(duì)象的屬性值,而不會(huì)自己定義規(guī)范。有關(guān)roadmap.path的工作原理可以看這里?以及?這里。
ok,讓md文件不發(fā)布很簡(jiǎn)單,那么views目錄下的按版本發(fā)布要求怎么實(shí)現(xiàn)呢?其實(shí)也是非常簡(jiǎn)單的配置:
fis.config.set('roadmap.path', [
{
reg : '**.md', //所有md后綴的文件
release : false //不發(fā)布
},
{
//正則匹配【/views/**】文件,并將views后面的路徑捕獲為分組1
reg : /^\/views\/(.*)$/i,
//發(fā)布到 public/proj/1.0.0/分組1 路徑下
release : '/public/proj/1.0.0/$1'
}
]);
roadmap.path數(shù)組的第二元素?fù)?jù)采用正則作為匹配規(guī)則,正則可以幫我們捕獲到分組信息,在release屬性值中引用分組是非常方便的。正則匹配 + 捕獲分組,成為目錄規(guī)范配置的強(qiáng)有力工具:
執(zhí)行? 在調(diào)用? 現(xiàn)在模塊的id有一些問(wèn)題,因?yàn)槟K發(fā)布會(huì)有版本號(hào)信息,因此模塊id也應(yīng)該攜帶版本信息,從前面的依賴(lài)樹(shù)生成配置代碼中我們可以看到模塊id其實(shí)也是文件的一個(gè)屬性,因此我們可以在roadmap.path中重新為文件賦予id屬性,使其攜帶版本信息: 重新構(gòu)建項(xiàng)目,我們得到了新的結(jié)果: you see?所有id都會(huì)被修改為我們指定的模式,這就是以文件為中心的編譯系統(tǒng)的威力。 以文件對(duì)象為中心構(gòu)建系統(tǒng)應(yīng)該通過(guò)配置指定文件的各種屬性。插件并不自己實(shí)現(xiàn)某種規(guī)范規(guī)定,而是讀取file對(duì)象的對(duì)應(yīng)屬性值,這樣插件的職責(zé)單一,規(guī)范又能統(tǒng)一起來(lái)被用戶(hù)指定,為完整的前端開(kāi)發(fā)體系設(shè)計(jì)奠定了堅(jiān)實(shí)規(guī)范配置的基礎(chǔ)。 接下來(lái)還有一個(gè)問(wèn)題,就是模塊名太長(zhǎng),開(kāi)發(fā)中寫(xiě)這么長(zhǎng)的模塊名非常麻煩。我們可以借鑒流行的模塊化框架中常用的縮短模塊名手段——?jiǎng)e名(alias)——來(lái)降低開(kāi)發(fā)中模塊引用的成本。此外,目前的配置其實(shí)會(huì)針對(duì)所有文件生成依賴(lài)關(guān)系表,我們的開(kāi)發(fā)概念定義只有components和component_modules目錄下的文件才是模塊化的,因此我們可以進(jìn)一步的對(duì)文件進(jìn)行分類(lèi),得到這樣配置規(guī)范: 然后我們?yōu)橐恍┠Kid建立別名: 再次構(gòu)建,在注入的代碼中就能看到alias字段了: 這樣,代碼中的? 還剩最后一個(gè)小小的需求,就是希望能像寫(xiě)nodejs一樣開(kāi)發(fā)js模塊,也就是要求實(shí)現(xiàn)define的自動(dòng)包裹功能,這個(gè)可以通過(guò)文件編譯的?postprocessor?插件完成。配置為: 所有在components目錄和component_modules目錄下的js文件都會(huì)被包裹define,并自動(dòng)根據(jù)roadmap.path中的id配置進(jìn)行模塊定義了。 最煎熬的一天終于過(guò)去了,睡一覺(jué),擁抱一下周末。 周末的天氣非常好哇,一覺(jué)睡到中午才起,這么好的天氣寫(xiě)碼豈不是很loser?! 居然浪費(fèi)了一天,剩下的時(shí)間不多了,今天要抓緊啊?。?! 讓我們來(lái)回顧一下已經(jīng)完成了哪些工作: 剩下的幾個(gè)需求中有些是fis默認(rèn)支持的,比如base64內(nèi)嵌功能,圖片會(huì)先經(jīng)過(guò)編譯流程,得到壓縮后的內(nèi)容fis再對(duì)其進(jìn)行base64化的內(nèi)嵌處理。由于fis的內(nèi)嵌功能支持任意文件的內(nèi)嵌,所以,這個(gè)語(yǔ)言能力擴(kuò)展可以同時(shí)解決前端模板和圖片base64內(nèi)嵌需求,比如我們有這樣的代碼: 無(wú)需配置,既可以在js中嵌入資源,比如 foo.js 中可以這樣寫(xiě): 編譯后得到:fis release -d ../release
?之后,得到構(gòu)建后的內(nèi)容為:<!doctype html>
<html>
<head>
<title>hello</title>
</head>
<body>
<script type="text/javascript" src="https://atts.w3cschool.cn/attachments/image/cimg/scrat.js"></script>
<script type="text/javascript">
require.config({
"deps": {
"components/bar/bar.js": [
"components/bar/bar.css"
],
"components/foo/foo.js": [
"components/bar/bar.js",
"components/foo/foo.css"
]
}
});
require.async('components/foo/foo.js', function(foo){
//todo
});
</script>
</body>
</html>
require.async('components/foo/foo.js')
?之際,模塊化框架已經(jīng)知道了這個(gè)foo.js依賴(lài)于bar.js、bar.css以及foo.css,因此可以發(fā)起兩個(gè)combo請(qǐng)求去加載所有依賴(lài)的js、css文件,完成后再執(zhí)行回調(diào)。fis.config.set('roadmap.path', [
{
reg : '**.md',
release : false,
isHtmlLike : true
},
{
reg : /^\/component_modules\/(.*)$/i,
//追加id屬性
id : '$1',
release : '/public/c/$1'
},
{
reg : /^\/components\/(.*)$/i,
//追加id屬性,id為【項(xiàng)目名/版本號(hào)/文件路徑】
id : '${name}/${version}/$1',
release : '/public/c/${name}/${version}/$1'
},
{
reg : /^\/views\/(.*)$/,
//給views目錄下的文件加一個(gè)isViews屬性標(biāo)記,用以標(biāo)記文件分類(lèi)
//我們可以在插件中拿到文件對(duì)象的這個(gè)值
isViews : true,
release : '/public/${name}/${version}/$1'
},
{
reg : '**',
useStandard : false,
useOptimizer : false
}
]);
<!doctype html>
<html>
<head>
<title>hello</title>
</head>
<body>
<img src="https://atts.w3cschool.cn/attachments/image/cimg/logo.png"/>
<script type="text/javascript" src="https://atts.w3cschool.cn/attachments/image/cimg/scrat.js"></script>
<script type="text/javascript">
require.config({
"deps": {
"proj/1.0.4/bar/bar.js": [
"proj/1.0.4/bar/bar.css"
],
"proj/1.0.4/foo/foo.js": [
"proj/1.0.4/bar/bar.js",
"proj/1.0.4/foo/foo.css"
]
}
});
require.async('proj/1.0.4/foo/foo.js', function(foo){
//todo
});
</script>
</body>
</html>
fis.config.set('roadmap.path', [
{
reg : '**.md',
release : false,
isHtmlLike : true
},
{
reg : /^\/component_modules\/(.*)$/i,
id : '$1',
//追加isComponentModules標(biāo)記屬性
isComponentModules : true,
release : '/public/c/$1'
},
{
reg : /^\/components\/(.*)$/i,
id : '${name}/${version}/$1',
//追加isComponents標(biāo)記屬性
isComponents : true,
release : '/public/c/${name}/${version}/$1'
},
{
reg : /^\/views\/(.*)$/,
isViews : true,
release : '/public/${name}/${version}/$1'
},
{
reg : '**',
useStandard : false,
useOptimizer : false
}
]);
var createFrameworkConfig = function(ret, conf, settings, opt){
var map = {};
map.deps = {};
//別名收集表
map.alias = {};
fis.util.map(ret.src, function(subpath, file){
//添加判斷,只有components和component_modules目錄下的文件才需要建立依賴(lài)樹(shù)或別名
if(file.isComponents || file.isComponentModules){
//判斷一下文件名和文件夾是否同名,如果同名則建立一個(gè)別名
var match = subpath.match(/^\/components\/(.*?([^\/]+))\/\2\.js$/i);
if(match && match[1] && !map.alias.hasOwnProperty(match[1])){
map.alias[match[1]] = file.id;
}
if(file.requires && file.requires.length){
map.deps[file.id] = file.requires;
}
}
});
var stringify = JSON.stringify(map, null, opt.optimize ? null : 4);
fis.util.map(ret.src, function(subpath, file){
if(file.isViews && (file.isJsLike || file.isHtmlLike)){
var content = file.getContent();
content = content.replace(/\b__FRAMEWORK_CONFIG__\b/g, stringify);
file.setContent(content);
}
});
};
fis.config.set('modules.postpackager', [createFrameworkConfig]);
require.config({
"deps": {
"proj/1.0.5/bar/bar.js": [
"proj/1.0.5/bar/bar.css"
],
"proj/1.0.5/foo/foo.js": [
"proj/1.0.5/bar/bar.js",
"proj/1.0.5/foo/foo.css"
]
},
"alias": {
"bar": "proj/1.0.5/bar/bar.js",
"foo": "proj/1.0.5/foo/foo.js"
}
});
require('foo');
?就等價(jià)于?require('proj/1.0.5/foo/foo.js');
了。//在postprocessor對(duì)所有js后綴的文件進(jìn)行內(nèi)容處理:
fis.config.set('modules.postprocessor.js', function(content, file){
//只對(duì)模塊化js文件進(jìn)行包裝
if(file.isComponents || file.isComponentModules){
content = 'define("' + file.id +
'", function(require,exports,module){' +
content + '});';
}
return content;
});
2014年02月15日 - 超晴
2014年02月16日 - 小雨
模塊化開(kāi)發(fā),js模塊化,css模塊化,像nodejs一樣的模塊化開(kāi)發(fā)組件化開(kāi)發(fā),js、css、handlebars維護(hù)在一起采用nodejs后端,基本部署規(guī)范應(yīng)該參考?express?項(xiàng)目部署按版本號(hào)做非覆蓋式發(fā)布公共模塊可發(fā)布給第三方共享js模塊化框架,支持請(qǐng)求合并,按需加載等性能優(yōu)化點(diǎn)project
- components
- foo
- foo.js
- foo.css
- foo.handlebars
- foo.png
//依賴(lài)聲明
var bar = require('../bar/bar.js');
//把handlebars文件的字符串形式嵌入到j(luò)s中
var text = __inline('foo.handlebars');
var tpl = Handlebars.compile(text);
exports.render = function(data){
return tpl(data);
};
//把圖片的base64嵌入到j(luò)s中
var data = __inline('foo.png');
exports.getImage = function(){
var img = new Image();
img.src = data;
return img;
};
define("proj/1.0.5/foo/foo.js", function(require,exports,module){
//依賴(lài)聲明
var bar = require('proj/1.0.5/bar/bar.js');
//把handlebars文件的字符串形式嵌入到j(luò)s中
var text = "<h1>{{title}}</h1>";
var tpl = Handlebars.compile(text);
exports.render = function(data){
return tpl(data);
};
//把圖片的b
更多建議: