停不下來的前端,自動化流程

作者: 元彥  來源: alloyteam  發布時間: 2014-08-15 08:26  閱讀: 11752 次  推薦: 15   原文鏈接   [收藏]  

  流程

  關于流程,是從項目啟動到發布的過程。在前端通常我們都做些什么?

  1. 切圖,即從設計稿中獲取需要的素材,并不是所有前端開發都被要求切圖,也不是所有前端開發都會切圖,但請享受學習新知識的過程吧。
  2. 創建模版(html、jade、haml)、腳本(javascript、coffeescript)、樣式(css、less、sass、stylus)文件,搭建基礎的項目骨架。
  3. 文件(jade、coffeescript、less、sass…)編譯
  4. 執行測試用例
  5. 代碼檢測
  6. 移除調試代碼
  7. 靜態資源合并與優化
  8. 靜態資源通過hash計算指紋化
  9. 部署測試環境
  10. 灰度發布現網

  工具化

  每個流程中的過程單元,我們抽象為一個Task,即任務。把可重復規則的過程進行工具化,如把JavaScript代碼壓縮過程工具化,而UglifyJS是具體執行任務的工具,CSS代碼壓縮器CleanCSS是具體執行任務的工具。

  工具文化幾乎是大平臺互聯網公司共有的特質,我們無法確定是工具文化驅動了Google、Facebook這類互聯網公司的快速發展,還是快速發展的需要使其在內推廣工具文化,但可以明確的是工具文化必不可少。在Facebook第二位中國籍工程師王淮的書中也提到提到:

  當時招聘他進Facebook的總監黃易山,是對內部工具的最有力倡導者:

他極度建議,公司要把最好的人才放到工具開發那一塊,因為工具做好了,可以達到事半功倍的效果,所有人的效率都可以得到提高,而不僅僅是工程師。

  在騰訊,工具文化雖沒有被明確指出,但大平臺公司對工具化的堅持是一致的:凡是被不斷重復的過程,將其工具化,綁定到自動化流程之中。技術產品也需要Don’t make me think的方式來推廣最佳實踐。總而言之:依靠工具,而不是經驗。

  自動化流程

  任務工具化是自動化流程的基礎,我想你已經聽說過任務運行器Grunt。Grunt幫助開發者把任務單元建立連接,如代碼編譯Task執行完后執行檢測Task,檢測Task執行完后執行壓縮Task。雖然Grunt是基于Node.js平臺,但其定位是個通用任務管理器,通用往往意味著更高的學習與實施成本。專注于Web開發領域騰訊有Mod.js來實施前端自動化,通過Mod.js有效的簡化Web開發自動化流程實施成本。

  實施Mod.js

  Mod.js并不是簡單的任務運行器,其內置集成了Web前端開發常用的工具集,覆蓋了80%的前端使用場景,而另外的20%則可通過Mod.js的插件機制來擴展。

  相遇

  Mod.js:https://github.com/modjs/mod 可通過NPM來安裝最新的版本, 在你來到Node.js的編程世界時已同時附帶了NPM,當前Mod.js最新版本0. 4.x要求Node.js要求>= 0.8.0

$ npm install modjs -g

  -g 參數表示把Mod.js安裝到全局,如此mod命令將會在system path內,方便在任何一個目錄啟動Mod.js任務。

  相識

  Mod.js通過Modfile.js文件驅動任務執行,可以手動創建一個Modfile.js文件,也可以通過模版初始化一個Modfile.js文件:

$ mod init modfile

  Modfile.js是一個Plain Node Module, 通過 Runner 對象來描述任務的具體執行過程:

// 暴露Runner對象module.exports = {}

  如是異步配置,則可通過回調模式傳遞Runner對象:

module.exports = function(options, done){
    setTimeout( function(){
        // 回調Runner對象
        var runner = {};
        done(runner);
    }, 1000)
} 

  借此一瞥通常Runner對象的全貌:

module.exports = {
    version: ">=0.4.3",
    plugins: {
        pngcompressor : "mod-png-compressor",
        compress      : "grunt-contrib-compress"
    },
    tasks: {
        asset: "asset",
        online: "online_dist",
        offline: "offline_dist",
        offlinePackage: "{{offline}}/package.zip",
        rm: {
            online: {
                dest: "{{online}}"
            },
            offline: {
                dest: "{{offline}}"
            }
        },
        replace: {
            src: './js/**/*.js',
            search: "@VERSION",
            replace: require('./package.json').version
        },
        build: {
            options: {
                src: ["*.html"]
            },
            online: {
                dest: "{{online}}",
                rev: true
            },
            offline: {
                dest: "{{offline}}",
                rev: false
            }
        },
        cp: {
            options: {
                src: ["./img/**"]
            },
            online: {
                dest: "{{online}}/img/",
                rev: true
            },
            offline: {
                dest: "{{offline}}/img/",
                rev: false
            }
        },
        pngcompressor: {
            src: "./img/**/*.png"
        },
        compress: {
            dist: {
                options: {
                    archive: '{{offlinePackage}}'
                },
                // includes files in path
                files: [
                    {
                        expand: true,
                        cwd: '{{online}}/',
                        src: ['*.html'],
                        dest: 'qq.com/web'
                    },
                    {
                        expand: true,
                        cwd: '{{online}}/img',
                        src: ['**'],
                        dest: 'cdn.qq.com/img'

                    }
                ]
            }
        }
    },
    targets: {
        default: ["rm", "pngcompressor", "replace", "build", "cp"],
        offline: ["default", "compress:dist"]
    }
} 
  • version 描述依賴的Mod.js版本
  • plugins 描述依賴的插件,支持Mod.js插件與Grunt插件
  • tasks 描述不同類別任務的執行
  • targets 描述不同組合的目標,目標是需執行任務的集合

  Mod.js的配置項追究極簡易懂,即使不懂JavaScript語法也能看懂配置與修改配置。

  相知

  在執行mod命令時,Mod.js會在當前目錄下查找是否存在Modfile.js文件。當找到Modfile.js文件時,Mod.js將讀取Modfile.js里的配置信息,如識別到有配置Mod.js插件,會自動安裝沒有安裝過的插件,插件不僅可以是發布到NPM的包,也可以是存在本地的自定義任務。

  Mod.js加載插件的方式是通過Node的require機制,然后執行暴露的exports.run,這與Mod.js內置任務的完全一樣的機制。

  在命令行下,通常執行mod時是需指定Modfile.js中某一特定目標,但當存在命名為default的目標或配置中只有一個獨立目標時,此時目標的指定是可選的,Mod.js會自動識別唯一的存在或default的目標:

targets: {
    dist: ["rm", "cp"]
} 
# 等價于 mod dist$ mod

  配置有default目標的場景:

targets: {
    default: ["rm", "cp"],
    other: ["compress"]
} 
# 等價于 mod default$ mod

  深入任務

  任務是具體執行的類別,從配置示例開始闡述:

tasks: {
    min: {
        src: "./js/*.js"
    }
} 

  以上配置了一個文件壓縮的min類別任務,src描述需要壓縮的文件:js目錄的所有js文件。src支持unix glob語法來描述輸入文件集,其匹配規則如下:

  匹配符:

  • “*” 匹配0個或多個字符
  • “?” 匹配單個字符
  • “!” 匹配除此之外的字符
  • “[]” 匹配指定范圍內的字符,如:[0-9]匹配數字0-9 [a-z]配置字母a-z
  • “{x,y}” 匹配指定組中某項,如 a{d,c,b}e 匹配 ade ace abe

  示例:

c/ab.min.js =>  c/ab.min.js
*.js        =>  a.js b.js c.js
c/a*.js     =>  c/a.js  c/ab.js c/ab.min.js
c/[a-z].js  =>  c/a.js c/b.js c/c.js
c/[!abe].js =>  c/c.js c/d.js
c/a?.js     =>  c/ab.js c/ac.js
c/ab???.js  =>  c/abdef.js c/abccc.js
c/[bdz].js  =>  c/b.js c/d.js c/z.js
{a,b,c}.js  =>  a.js b.js c.js
a{b,c{d,e}}x{y,z}.js  => abxy.js abxz.js  acdxy.js acdxz.js acexy.js acexz.js 

  更多任務配置規則深入:https://github.com/modjs/mod/blob/master/doc/tutorial/configuring-tasks.md

  如任務沒有配置dest,默認在輸入文件同級目錄下輸出.min后綴的文件:

uglifyjs Minifying ./js/unminify.js -> js/unminify.min.js
uglifyjs Original size: 1,393. Minified size: 449. Savings: 944 (210.24%)

  內置的min任務支持三種文件類別的壓縮,JavaScript、CSS與HTML,是對uglifyjscleancsshtmlminfier任務的代理。min通過識別文件后綴進行具體任務的分發。所以min任務的src選項需指定具體的后綴。通常每個不同類別的任務都支持srcdest,且Mod.js會結合實際項目中常見的場景,dest往往都是可選的,如上min任務默認的dest是在當前目錄下輸出待.min后綴的文件,同時后綴名是支持通常suffix選項配置的。

  每個內置任務支持的所有參數選項可通過Mod.js的在線文檔查看:https://github.com/modjs/mod/tree/master/doc

  同時有豐富的演示項目來輔助不同任務的配置:

  不可或缺的插件機制

  Mod.js支持2種生態的插件:Mod.js 與 Grunt。插件的配置同樣是在Runner對象下:

plugins: {
    // Mod.js NPM 插件
    sprite: "mod-stylus",
    // Mod.js 本地插件
    mytask: "./tasks/mytask"
    // Grunt NPM 插件
    compress: "grunt-contrib-compress"
} 

  同樣附上演示項目來輔助不同插件的配置:

  如插件未安裝在項目目錄下或與Mod.js同級的全局目錄下,Mod.js會自動通過NPM安裝配置的插件。什么情況需要手動把插件安裝在全局下?在實際項目開發中我們往往會對同一項目拉不同的分支進行開發,他們依賴的插件版本是相同的,此時如果在不同分支都安裝一個冗余的插件版本項目是多余的,所以當你確定這是個插件是共享的,可以手動通過npm install -g mod-stylus來安裝到全局。同時項目目錄中插件版本權重永遠是高于全局的,如需避免加載全局的版本,只需手動在項目安裝即可。

  限于篇幅,更多插件相關說明可訪問以下主題頁面:

  零配置快速項目構建

  雖說是零配置構建項目,不如稱之為基于DOM的項目構建,這個主題的內容與我之前在Qing項目中討論的主題的一致的,在此只附上示例:

  另外免配置文件對Sea.js 2.1+項目的支持正在開發中,會下Mod.js的下一迭代中支持。

  服務化

  了解完如何實施Mod.js進行自動化時,僅是停留在工具的層面,如何將其進一步的提升?了解一個事實,服務優于工具。如何將其封裝成服務,用戶無需安裝Mod.js,無需執行命令,只需做一次事情:提交代碼,中間的過程無需關注,最終把持續構建的結果反饋給用戶。這是下一步需要去完善的,建立接入機制,讓工具以服務的形式完全融入流程中。

15
0
 
標簽:前端 自動化
 
 

文章列表

arrow
arrow
    全站熱搜

    大師兄 發表在 痞客邦 留言(0) 人氣()