4. 前端工程化開發實踐 由於Nodejs 、npm的環境搭建往上很多,這裡就不過多介紹它們了。 這裡我們將更多介紹FIS3、RequireJS 、r.js。 4.1 模塊化開發: 4.1.1 開發目錄結構 左圖為開發目錄結構, 右圖中新增js 目錄、fis-conf.js文件,js 目錄用來存放r ...
4. 前端工程化開發實踐
由於Nodejs 、npm的環境搭建往上很多,這裡就不過多介紹它們了。
這裡我們將更多介紹FIS3、RequireJS 、r.js。
4.1 模塊化開發:
4.1.1 開發目錄結構
左圖為開發目錄結構,
右圖中新增js 目錄、fis-conf.js文件,js 目錄用來存放require.js的頁面級入口文件
4.1.2 HTML文件的模塊化處理
任何頁面都可以拆分為若幹組件,在開發環境下,可以迅速定位組件位置,修改組件
FIS3為我們提供了方便的資源嵌入功能http://fis.baidu.com/fis3/docs/user-dev/inline.html
簡單來說,我們可以如同模板開發一樣去寫HTML頁面,例如:
這個首頁頁面本身的樣式和代碼極少,頁面內容都是由” ?__inline”功能從其他頁面引入了,
如:banner.html
當文件編譯時,FIS3會自動幫我們把這些地方替換為文件中的HTML代碼:
編譯後的index.html:
可以看到,FIS3幫我們將banner.html中的代碼完成寫入了index.html。
這裡我們完成了簡單的頁面代碼模塊化分離,但是這遠遠還不夠,因為我們的頁面還需要包括CSS文件,JS文件,以及一系列的圖片文件等等。那麼這些東西該這麼完成模塊化分離,然後再打包呢。對於CSS我們就需要用到LESS的,js則需要Requirejs的幫助。
4.1.3 JS文件的模塊化處理了
這裡我們需要使用到Requirejs,前面提到過,它是AMD模式的一個實現。由於js語言的歷史原因,它在很長一段時間都算不上一個嚴謹的言語,不過經過多年來的不斷努力,人們提出了許多增強它,規範它的方案,這些規範的目的都是為了 JavaScript 的模塊化開發,特別是在瀏覽器端的。目前這些規範的實現都能達成瀏覽器端模塊化開發的目的。
Requirejs 首先需要一個requirejs.config的配置,該配置的目的在於確定文件間的依賴關係,設定各個文件的別名,設定文件的載入順序等等。
上面是一個簡單的配置,baseUrl定義了一個相對文件所在目錄的相對路徑,paths設置了相關文件的別名,shim規定文件間的依賴關係,比如baseUI模塊依賴jquery模塊,因此,baseUI需要在jquery載入完後載入。http://www.requirejs.cn/ 詳細配置選項查看這裡。
對於requirejs.config 定義的位置,我嘗試過三種方式:
u 每個入口文件中都定義一次
u 統一到config.js中去定義,在載入時優先require這個文件,然後在回調函數裡面在寫頁面的依賴
這樣做到時解決了冗餘的問題,但是require的嵌套顯然不太符合作者的初衷.
u 統一到config.js中去定義,然後加require.js和config.js打包到一起,在引用入口文件前就同步調用了。
這樣做相當於全局定義了require.config並且在頁面中同步調用,一定是會在入口文件前,解決了之前的問題
註意require.config中shim只用做兩個功能,一個是表明依賴順序關係,一個是載入不符合AMD規範的js文件。不要用作模塊載入。
接下來就是入口文件和模塊文件的編寫,入口文件我認為應該是每個一個,這樣能保證不會載入多餘的文件進來。當然,在特殊情況下,可以不同頁面引用同一個,靈活應用。
對於模塊文件,我推薦的書寫方式如下,在對象中定義方法,並將對象作為介面暴露,提供給其他模塊使用
特別提示一點,無論是入口文件,還是模塊文件,只要是需要使用的依賴就要寫到依賴數組中,不要想著a依賴過b,我現在只要寫依賴a那邊b也自動依賴了,這樣是違反requirejs的初衷的。
4.1.4 css文件的模塊化處理
目前來說,有兩種方式來對css文件做模塊化處理
u 利用LESS的@import引入模塊
u 利用FIS3的“聲明依賴”功能引入模塊
兩者區別在於@import會在LESS文件編譯階段將引用的LESS文件加入該文件中,而@require是在文件打包階段將各個css文件合併到一起。
1.1.5 圖片的處理
FIS3的fis-spriter-csssprites插件即可幫助我們生成頁面級別的雪碧圖
4.2 自動構建和優化
4.2.1 FIS3 介紹
u FIS3 是基於文件對象進行構建的。
u FIS3有自己的內置語法,實現了“內容嵌入”,“定位資源”,“聲明依賴”三個功能。
u FIS3 編譯的整個流程都是通過配置文件fis-conf.js來控制的。
u FIS3 定義了一種類似 CSS 的配置方式。固化了構建流程,以期讓工程構建變得簡單。
u FIS3 提供了文件指紋的功能,通過分析文件大小,在文件名中添加MD5碼,來解決文件更新時的瀏覽器緩存問題。
以上是我對FIS3一點理解,詳細的教程請移步FIS3網站查看。
FIS3教程:http://fis.baidu.com/fis3/docs/beginning/intro.html
強烈建議跟著教程走一遍,對FIS3有一點瞭解後再繼續往下看
目前使用到的最重要的幾個功能:
u FIS3編譯功能,通過配置文件fis-conf.js我們可以輕鬆的告訴FIS3該如何去處理我們的前端文件,具體語法和使用方法請查看教程
在這個HTML文件中我們引用了一個CSS文件,一個LESS文件,同步引用了html5.js,require.js以及config.js,此外我們還通過Requirejs非同步引入了一個模塊名為index_main的js模塊。
那麼根據上面fis-conf.js中的配置,我們的文件將會構建成什麼樣子呢。
首先,我們的配置命中了當前目錄及其子目錄下的所有.less文件,並且調用了插件fis-parser-less插件將.less文件轉換為.css文件後輸出。
然後我們在文件打包階段調用了fis-postpackager-loader插件,用過allInOne這個配置,將頁面中同步引用的CSS文件、JS文件分別打包。這裡我們同步引用的js文件有html5.js,require.js以及config.js。
但是仔細看,在我們HTML代碼中有個<!--ignore-->的註釋,這裡就是為了告訴FIS3,打包時請忽略這個文件,因此FIS3打包會跳過html5.js,然後打包require.js、config.js。並將其輸出為 libs/require_conf.js文件。(由於html5.js需要dom載入前調用,所以不打包它)
對於CSS文件,我們在html文件中引入了一個reset.css,同時我們通過前面一步編譯出了一個index.css,所以這裡FIS3會把這兩個文件打包,然後輸出到index.html_aio.css
文件中,配置中的${filepath}就代表當前文件路徑
u FIS3給我們提供了一個本地的簡易Nodejs伺服器,使用命令行 fis3 server start就可以啟動。並且該服務一直存在後臺,不關機/重啟 或者 主動停止服務,該服務不會關閉,另外使用命令行fis3 server open可以打開伺服器所在文件夾,給我們前端開發提供了一個非常方便的伺服器環境。一般來說我們可以通過127.0.0.1:3000來訪問這個本地伺服器。
u FIS3的有強大的監視自動刷新功能,當你的文件夾下任何文件發生變動時,FIS3會自動刷新頁面並且,重新編譯文件。這個功能需要fis3 release –wL來激活。
4.2.2 使用r.js
在使用FIS3的過程中,發現非同步的JS文件的打包,FIS3的庫目前支持還不足,所以我決定暫時使用r.js去替代。
當我在用FIS3打包整個項目之前,我會先用r.js對requirejs的依賴進行打包。如果FIS3一樣,我們需要編寫一個配置文件來告訴他改如何打包,配置文件命名為build.js
以上是一個簡單的build.js配置,更多配置可以參考http://www.chenliqiang.cn/node/22
前面提到過require.config中最好不要通過shim依賴模塊,這是因為這會造成打包後多次拉取文件,因此全部放在require的依賴數組中處理。
這裡配置完後,我們通過 node r.js –o build.js 進行打包,生成的新文件夾temp-build
4.2.3 使用FIS3
使用完r.js,我們開始使用FIS3構建整個項目
在這個配置文件中,我們設定了兩套構建規則,如同CSS語言中的媒體查詢一樣。我們這裡使用media來配置第二套構建規則。
在命令行中輸入fis3 release可以開始執行構建
如果我要執行第二套方案只需要寫為fis3 release temp 即可
上圖中的-d命令代表修改輸出目錄到../temptest,FIS3構建時還有其他參數可以選擇,具體可以參考FIS3的文檔。
完成構建後我們可以看到,我們頁面的請求數減少了,並且文件都帶上了MD5指紋
4.2.4 使用過程中遇到的問題
由於我們使用了文件指紋,所以每個文件的文件名中間會插入一個表示文件大小的MD5碼。
比如index.js會變成index_d82af77.js,根據FIS3“定位資源”的規則,構建時FIS3會自動替換掉html中的script、link、style、video、audio、embed等標簽的src或href屬性中的值,但是使用Requirejs時在data-main中的非同步引入的文件和在config.js中配置的路徑就沒有那麼好運了。
解決方法:
u前面有提到全局配置require.config,事先就將data-main中文件路徑用模塊名替代。這樣能解決data-main中路徑無法替換的問題。
u這裡可以使用FIS3提供的資源定位能力,在config.js中使用__uri()函數解決該問題
5. 結語
這篇文章寫於去年4月,由於沒有註冊博客園的賬號,因此現在才發佈過來。一年多的時間前端工程領域的變化很大,我們團隊也經歷了FIS、grunt到現在webpack的變化,我也希望通過這篇基礎文章 ,拋磚引玉,讓大牛們更多來分享下你們的前端工程化經驗。