構建的核心是資源管理。簡單說,構建就是把前端工程師開發的源代碼進行編譯、壓縮、打包等一系列操做,最終產出能夠直接上線或者可供後端工程師的資源。javascript
構建能夠劃分爲純前端構建和先後端協做構建。php
這兩個不是專業術語,若是你有更合適的稱謂,歡迎指正。css
所謂純前端構建,就是說不涉及後端模板的構建,通過構建以後的前端代碼能夠直接上線。這種情形下大可能是數據驅動UI的web應用,模板只負責提供空白的容器和基礎的靜態資源,UI的文檔結構交由前端JavaScript實現。這個過程可使用一些框架,好比近期較流行的React、Vue等;也使用較輕量級的JavaScript模板工具,好比的underscore template、jsmart、Mustache等;甚至能夠直接拼接字符串。html
先後端協做構建與純前端構建惟一的不一樣是加入了對後端模板的依賴,這也是目前絕大多數web應用的工做模式。這種模式下,構建工具要額外處理模板中對靜態資源的引用地址。咱們在淺析前端工程化一文中提到的即是先後端協做的構建模式,也是本文將要討論的方向。前端
下面咱們細化資源管理的每一個關鍵點,共同探討一下前端工程中構建環節的工做內容和麪臨的問題。java
若是是純前端構建(不涉及後端模板),在資源管理方面,編譯工具須要完成的事情包括:es6
是否合併這一步由用戶選擇,好比項目中使用requirejs做爲前端模塊化方案,考慮到緩存、異步等問題可能選擇不合並。這種狀況下每每須要在本次構建產出的資源依賴表的基礎上進行二次構建,後續會詳細說明。web
一套完整的構建流程以下圖所示:
算法
具體構建流程中的各個行爲並非嚴格按照上圖的先後順序進行,能夠自行安排。後端
上圖中提到的各個構建行爲中,代碼審查、預編譯、uglify&compress、hash指紋實現較容易,各構建模式中沒有差別,本文便再也不贅述。而依賴打包管理和模板構建是須要額外配置而且方案不惟一,下面詳細探討這兩個行爲的具體內容。
依賴管理之因此方案不惟一是由於每一個項目可能會採用不一樣的客戶端模塊加載方案(AMD/CMD/CommonJS)。構建平臺自己不該該面向某一種方案,而應該是可配置的。
好比某個項目客戶端的模塊化方案採用AMD,使用requirejs做爲模塊加載器,那麼在構建平臺產出上述資源依賴表以後,還須要對requirejs進行配置,這個階段咱們能夠稱爲二次構建。
二次構建要用到依賴分析以後的資源依賴表和release以後產出資源定位表。假設資源依賴表格式以下:
{ 'a.js': { deps:['b.js','c.js'] } 'c.js': { deps: ['d.js'] } 'e.js': { deps: ['f.js'] } }
資源定位表的格式以下:
{ 'src/js/a.js': 'release\js\a.sdf43n.js', 'src/js/b.js': 'release\js\b.sdf43n.js', 'src/js/c.js': 'release\js\c.sdf43n.js', 'src/js/d.js': 'release\js\d.sdf43n.js', 'src/js/e.js': 'release\js\e.sdf43n.js', 'src/js/f.js': 'release\js\f.sdf43n.js', }
在二次構建階段,requirejs根據資源依賴表和資源定位表須要做出以下配置:
requirejs.config({ baseUrl: '/', path: { 'a.js': 'release\js\a.sdf43n.js', 'b.js': 'release\js\b.sdf43n.js', //... }, shim: { 'c.js': { deps: ['d.js'] } //... } });
雖然同步依賴的文件原則上應該打包成一個文件,可是構建平臺不該該制定一些條律,因此在requirejs配置完成以後,構建平臺應該還須要提供是否壓縮打包的配置項。
此外,若是開發階段使用es6語法,客戶端使用AMD方案的話,在二次構建以前還須要將es6 module模塊編譯爲AMD規範,這一步在預編譯階段完成。
模板構建的核心問題是如何同步更新靜態資源的引用地址。除此以外,模板中每每還包含一些由Controller輸出的動態數據,在構建過程當中須要謹慎處理各模板引擎的語法。
目前對模板的處理分爲兩種模式:由前端負責構建和由後端負責構建。
這兩種模式不只僅是分工的不一樣,同時涉及開發方案的不一樣。
若是模板由前端構建工具進行編譯,交到後端開發者手裏的模板中對靜態資源的引用地址是已經更新後的url,後端開發者不須要對模板進行額外操做即可以直接進行下一步流程(測試、部署)。
可是前端構建工具必須謹慎處理模板引擎的語法,以避免形成「誤傷」。後端模板引擎多種多樣,前端構建工具很難作到百分百覆蓋。因此一般狀況下須要對模板中靜態資源的url添加額外標識位,以處理文本的方式識別標識位並進行替換。好比:
<script src='[__static-start__]src/js/index.js[/__static-end__]'></script>
上述代碼中將index.js
的url用類ubb格式的開閉標籤包裹起來。假設經編譯後index.js
的資源定位表以下:
{ 'src/js/index.js': 'static.daojia.com/js/index.sfdf232.js' }
前端構建工具首先獲取模板文件的文本內容,正則出[__static-start__]src/js/index.js[/__static-end__]
,而後替換爲static.daojia.com/js/index.sfdf232.js
。
以上的操做每每很是耗時,而且不能保證百分百正確率。
模板有後端構建的意思是,後端開發人員對模板引擎進行擴展,書寫一個模板引擎語法的資源尋址function。好比php使用smarty模板引擎實現一個cdn
方法:
<?php /* * Smarty plugin * ------------------------------------------------------------- * File: function.cdn.php * Type: function * Name: cdn * Purpose: transform internal cdn path to online format * ------------------------------------------------------------- */ function smarty_function_cdn($params, Smarty_Internal_Template $smarty){ //... }
還能夠針對不一樣類型的靜態資源擴展對應的cdn尋址方法:
<?php /* * Smarty plugin * ------------------------------------------------------------- * File: function.js.php * Type: function * Name: js * Purpose: print script tag by url * ------------------------------------------------------------- */ require_once('function.cdn.php'); function smarty_function_js($params, $smarty){ //... }
而後前端開發人員在編寫smarty模板時即可以使用以下語法引入靜態資源:
{js url="/src/js/index.js"}
前端構建工具只須要處理靜態資源便可,後端模板在部署上線後會將index.js
的url更新爲線上地址。
模板交由後端構建的優勢是能夠對每種模板引擎有針對性的處理,並且是很工程化的構建方式;缺點是須要額外書寫尋址function,可是這個缺點相對於優勢來講微不足道。
綜上所述,模板前端構建和後端構建的對好比下:
根據表格的對比數據能夠看出模板後端構建相比前端構建有很大優點。可是做爲構建平臺,應該同時支持兩種模式。因此在開發構建平臺的時候,開發者應該提供前端構建的功能接口,由用戶選擇是否採用。
本文簡單講述構建平臺在不一樣開發模式下對應的構建方案。以上內容是筆者的一些經驗和思考,確定會有不足和錯誤之處,歡迎你們反饋,共同探討。