• <noscript id="eom2a"><optgroup id="eom2a"></optgroup></noscript>
    <tt id="eom2a"><small id="eom2a"></small></tt>
    <input id="eom2a"></input>
  • <div id="eom2a"><small id="eom2a"></small></div>
    <td id="eom2a"><small id="eom2a"></small></td>
  • 您的位置:知識庫 ? Web前端

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

    作者: 元彥  來源: alloyteam  發布時間: 2014-08-15 08:26  閱讀: 11614 次  推薦: 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
    標簽:前端 自動化

    Web前端熱門文章

      Web前端最新文章

        最新新聞

          熱門新聞

            黄色网_免费在线黄色电影_黄色成人快播电影_伦理电影_黄色片