1. 前端自動化工作流簡介
每種項目都有自己特定的開發流程、工作流程。從需求分析、設計、編碼、測試、發布,一個整個開發流程中,會根據不同的情況形成自己獨特的步驟和流程。一個工作流的過程不是一開始就固定的,而是隨着項目的深入而不斷地改進,期間甚至會形成一些工具。例如當年大神們在Linux寫C語言,覺得每次編譯好多文件好麻煩,就發明了makefile。不同代碼的管理好麻煩,然后就發明了git、SVN等等。
一個工作流程的好壞會影響你開發的效率、開發的流程程度,然后間接影響心情,打擊編碼積極性。所以我認為開發一個項目的時候,編碼前把工作流程梳理清楚確定下來是一個非常重要的步驟。並且這個流程要在真實環境中不停的改進。
對於要負責頁面結構和內容、外觀、邏輯的前端來說,一個好的工作流至關重要。而且這里中沒有銀彈。要根據具體項目所使用的框架、應用場景來進行調整獨特的工作流。
我會介紹一個我經常使用的前端工作流,這個工作流只是一個原始的流程,一般來說,我會根據不同項目的不同來在這個基礎上進行調整,形成每個項目獨特的流程。所以這里的重點是領會構建工作流的思路,然后學會舉一反三。
一個前端自動化開發流程中,我覺得至少需要做到以下幾點:
- 良好的模塊化
- 自動化編譯
- 自動化測試
- 實時刷新頁面
- 自動化打包、壓縮發布
能用機器的地方就不要自己動手,除了上述必備的幾點,有時候要根據特定的情況編寫一些Python、Nodejs、Shell腳本來避免重復的操作。好好呵護你的F5和稀疏的腦神經,男人要對自己好一點。
2. 儲備知識
在正式介紹之前會先做一些儲備知識的介紹,也會略過一些你可能不懂的知識。懂的話可以跳過,遇到不懂的可以自己Google,不要百度。
2.1 工程目錄
我的工程目錄一般是這個樣的:
├─assets/
│ └─images/
├─bin/
├─dist/
├─lib/
├─src/
│ ├─coffee/
│ │ └─main.coffee
│ └─less/
│ └─main.less
├─test/
│ └─specs/
├─node_modules/
├─index.html ├─Gruntfile.coffee ├─package.json ├─.gitignore └─README.md
所有子目錄名稱很多都其實源於古老的C語言工程。
assets:一般存放的是圖片、音頻、視頻、字體等代碼無關的靜態資源,我一般只有圖片,有時候也會新建一個fonts文件夾什么的。
bin:binary的縮寫,這個名字來歷於我們古老的C語言工程,因為一般C語言要編譯成可執行的二進制文件什么的,后來基本成為了一種默認的標注。所以前端編譯好的文件也會存放在bin/目錄下。
dist:distribution的縮寫,編譯好的bin中的文件並不會直接用於發布,而是會經過一系列的優化操作,例如打包壓縮等。最終能夠部署到發布環境的文件都會存放在dist里面,所以dist里面是能夠直接用到生產環境的代碼。
lib:library的縮寫,存放的是第三方庫文件。例如你喜歡的jquery、fastclick什么的。但是接下來你會看到,在我們的模塊化方式中,這個文件夾一般是比較雞肋的存在。
src:source的縮寫,所有需要開發的源代碼的存放地,我們一般操作地最多的就是這個文件夾。簡單地分為coffee、less兩個文件夾,存的是邏輯代碼和樣式(我一般用CoffeeScript和LessCss,當然你也可以改成你喜歡的語言,JS,TS,LS,SASS,思路是一樣的)。你看到兩個文件夾下分別有main.coffe、main.less,這其實是邏輯代碼和樣式代碼的主要入口文件,會把其他模塊和樣式引進來,通過某種機制合成一個文件。接下來會詳細解釋。
另外,這個目錄的組織方式會根據實際情況多變。有時候你會需要html模板,可能會多一個tpl/目錄。也許你的目錄不是這種基於文件類型的層次組織,而是基於頁面部件的組織,就可能出現components/目錄,然后下面有很多個頁面部件的目錄,每個子目錄有自己的coffee、less、html。(這種形式也變得逐漸流行。因為基於文件類型目錄,當工程復雜起來的時候,就會變得異常難以維護,基於部件就會相當方便)。
test:使用測試驅動(TDD)開發進行編程,這里存放的都是測試樣例。
index.html:頁面文件
接下來幾個文件都不解釋,不了解的可以先預習NodeJS、Git、Grunt這幾個東西。
2.2 模塊化
說起前端模塊化又是一個可以長篇大論話題。前端模塊化的方式有很多種,年輕人最喜歡用的就是RequireJS、SeaJS什么的,看到這些模塊化工具的時候感覺就像自己的第一雙滑板鞋那樣那么興奮。其實這種AMD、CMD都需要引進一個庫文件來做模塊化工具,而且配置復雜,各種異步加載問題多多。后來我發現其實最clean、直接、方便、強大模塊化方式當屬substack大神的真.Browserify。
它可以基於NodeJS平台實現模塊化的工具,你可以像組織NodeJS代碼那樣組織自己的前端工程,所有的模塊都可以像NodeJS那樣直接require進來。提供一個入口文件(如上的main.coffee)給Browserify,它會把這個入口文件的所有依賴模塊都打包成一個文件。最終的文件不依賴於Browserify,最終的文件就是你的邏輯代碼的組合。
而且Browserify和NodeJS的模塊兼容性很好,一些NodeJS自帶的模塊例如util、path都可以用到前端中。你用npm安裝的庫,也可以通過Browserify用到前端中!例如我想用jQuery,我只需要:npm install jquery --save
。然后在main.coffee中:
$ = require "jquery" // play with jquery
相當貼心。
(Browserify具體用法查看官網文檔)
2.3 流程自動化工具
其實自動化方式可以有很多種,你可以:
- 配置npm的script,直接用npm來進行自動化任務管理。
- 使用古老的makefile和shell腳本
- Grunt
- Gulp
前兩種方式更適合NodeJS開發服務端的應用場景,前端一般更適合用后兩種。
目前使用的是Grunt,選擇它是因為它社區大、插件多、成熟。但是我更看好Gulp基於流(Stream)的機理,這種繼承於Unix思想的無與倫比的實現方式着實可以讓它在性能上和Grunt拉開差距。Grunt基於文件實現方式是在是:太!慢!了!
(Grunt具體用法可以見官網文檔)
2.4 測試
測試又是一個龐大的話題。在國外,前端TDD、BDD開發已經相當成熟,各種酷炫的工具Jasmine、Mocha、Tape等等,可能是我比較孤陋寡聞,貌似國內很少見到這些工具的使用。
其實前端是很難做到完全測試驅動開發的,它本身涉及到許多主觀判斷因素,例如動畫是不是按照預想的那樣移動等等。但是邏輯代碼和前后端接口邏輯是可以測試的。所以引進測試驅動開發的一個非常大的好處就是:只要接口確定了,前后端可以分離開發,前端不用再“等后端API實現”了。
在我們的工作流中,使用MochaJS作為測試套件,ChaiJS作為斷言庫,Sinon做為數據mocking和函數spy。具體用法可以看各自的官網。
(對前端測試驅動開發不了解的同學可以Google相關資料或查閱相關書籍)
3. 自動化工作流
3.1 模板
這個工作流的模版已經存放到了github上,大家可以clone下來進行本地測試一下:https://github.com/livoras/feb.git
運行步驟:
- 電腦上必須先按安裝好Nodejs和npm
-
安裝browswerify,coffeescript,和grunt:
npm install browswerify coffee-script grunt-cli -g
-
把倉庫fork到本地,進入工程目錄,安裝依賴:
npm install
-
然后運行grunt命令
運氣好的話你可以看到這樣的界面:
然后,你會發現工程目錄下多了一個bin文件夾,那就是我們剛編譯好的文件存放在bin中。
然后打開瀏覽器,進入http://localhost:3000 ,可以看到:
現在我們修改src/less/main.less文件,把body改成黑色看看:
然后回到瀏覽器看看:
說變就變,非常哦妹子(amazing)是不是?
工作流分兩個簡單的步驟:
- 開發時
- 分布時
現在來介紹一下。
3.2 開發時
我們來看看gruntfile的100~108行:
其實grunt干了這么幾件事:
- 開啟本地服務器進行調試:使用grunt的一個connect插件,開啟了一個本地服務器,localhost:3000,工程目錄為根目錄。
- 刪除原來已經之前已經過時的編譯文件:刪除整個bin文件夾
- 編譯coffeescript並且使用browserify進行依賴合並:將src/coffee/下面的main.coffee作為入口,把所有依賴模塊編譯成js並且合並成一個文件,存放到bin/js/目錄下。打開bin/js/你可以看到下面有一個main.js。細心但話,你會發現,其實main.coffee是依賴同目錄下的一個叫another-module.coffee的模塊的。在編譯的時候,browserify會分析整個main.coffee的依賴樹,然后找到所有依賴進行合並,所以你看到的bin/js/main.js其實是包含了兩個模塊的內容。所以我們可以用Nodejs的方式寫模塊,前端只需要合並好的文件就可以了。
- 編譯less:將src/less/main.less編譯到bin/css/目錄下,同樣的, Less也是可以類似coffee的方式引用模塊(通過
import
)。所以我們的樣式也是萌萌噠模塊化了。 - 運行測試:所有的測試存放在test/specs下,編譯好以后,grunt會運行moch運行測試樣例。你在窗口中可以看到我們一共有三個測試運行並且通過了。
- 監控文件變化,一旦文件變化,重新執行3~5步驟。並且自動刷新瀏覽器:借助於grunt的watch插件,我們可以做到一旦文件修改的時候,就重新編譯coffeescript,less,運行測試,並且自動刷新瀏覽器。
有了這么一個流程,你就可以很輕松地寫前端的邏輯和樣式,並且都是以模塊化的方式。
3.3 發布時
好了,代碼都寫完了。我需要把我的代碼部署到服務器上。很簡單,只需要命令行中執行:
grunt build
你就會發現工程目錄下多了一個dist文件夾,進入里面,可以看到:
直接打開index.html:
居然可以直接打開,也是非常哦妹子是不是?
我們看看grunt的build任務:
grunt build干了這么幾件事情:
- 刪除之前編譯過的文件,同上。
- 刪除之前發布的文件,也就是刪除整個dist目錄。
- 編譯coffee和less,同上。
- 測試,發布前還是需要看看有沒有問題嘛。
- uglify,把bin/js/main.js混淆壓縮,放到dist/js/下。
- cssmin,把bin/css/main.css混淆壓縮,放到dist/css下。
- 復制assets目錄到dist下
- 復制index.html,做一些處理(更改相對路徑等),存放到dist/下
你可以看到dist目錄下的文件js和css文件都是經過壓縮的,現在dist中的文件夾已經ready了,你隨時都可以直接放到服務器上了。
4. 最后
上面其實是一個非常簡陋的流程,在實際要做的流程化要比這個復雜多,例如要考慮組建目錄自動化構建,版本管理自動化,部署自動化,圖片合並優化等等。主要有這個意識:* 不要做任何重復的工作,能自動化到地方都可以想法設法做到自動化 *。
上面也跳過了很多基礎知識,這些是你需要知道的:
- Grunt的使用
- Nodejs的基本使用
- 模塊化概念
- TDD測試的概念和基本測試套件的使用
- Coffee,Less,Browserify但使用等
我甚至直接跳過了構建整個流程的過程,也跳過了測試如何編寫。其實其中很多細節都可以拓展來講,測試,模塊化等,接下來博客也許會往這個方向去寫。