如何構建自動化的前端開發流程
如今的前端開發中,已經不再只是一些簡單的靜態檔案了,對於很多Web App來說,前端程式碼甚至比後端程式碼要更加複雜,更加難於管理,例如:
- 我們有許多的第三方庫的依賴需要管理;
- 我們有獨立的前端測試需要自動執行;
- 我們還有很多程式碼需要在釋出時進行打包壓縮;
- ⋯⋯
所以構建一個自動化的前端開發流程是非常必要的,但現在前端開發流程的構建是百花齊放,沒有一個統一的標準,還有很多依賴於後端的架構來做前端開發管理。例如在Rails開發中,就有各種前端庫的gem包。但是這種依賴於後端框架的管理方式有許多問題:
- 許多gem包的維護者並不是前端庫的維護者,所以更新不一定即時;
- 不利於前端程式碼與後端程式碼做分離;
- 增加了前端開發者的學習和使用成本;
- ⋯⋯
於是現在出現了一些不依賴於後端程式碼(雖然還是要依賴Node.js⋯⋯)的管理工具,對於前端開發者非常友好,例如:YEMAN、Jam、volo、component、Brunch⋯⋯但是這些工具都或多或少有自己的一些問題,所以我決定用一些更輕量的工具(bower、grunt)來搭建自己的前端開發流程。本文的例子來自本人正在開發的一個專案,可以在github上檢視所有的程式碼。
什麼是開發流程?
在我看來一個完整的開發流程應該包括:
- 本地開發環境的初始化
- 第三方依賴的管理
- 原始檔編譯
- 自動化測試
- 釋出到pipeline和各個環境
而現代的開發流程,就是要使上面的各個部分都可以自動化,一個命令就可以使這些流程都自動走完,並且快速的得到錯誤或通過的反饋,讓我們可以方便快速的修復錯誤和release。
本地開發環境的初始化
這裡我使用的工具是Node.js和NPM,它們都基於JavaScript,使用Json來配置,對於前端開發人員非常友好。
安裝完成Node.js和NPM後,在專案根目錄下建立NPM的配置檔案package.json:
{ "name": "Project Name", "version": "0.0.1", "description": "Project Description", "repository": { "type": "git", "url": "git://github.com/path/to/your_project" }, "author": "Author Name", "license": "BSD", "readmeFilename": "README.md", "gitHead": "git head", "devDependencies": { "grunt": "latest", "grunt-contrib-connect": "latest", "grunt-contrib-concat": "latest", "grunt-contrib-jasmine": "latest", "grunt-contrib-watch": "latest", "grunt-contrib-compass": "latest" } }
其中最重要的一個配置項是devDependencies,這是用於開發的依賴,例如:自動化測試、原始檔編譯等等,其中各個依賴的作用和用法將會在後面講到。而前端生產程式碼的依賴會使用另一個工具來管理,也在後面講到。建立完成以後執行npm install,NPM就會將這些依賴都安裝到專案根目錄的node_modules資料夾中。
第三方依賴的管理
這裡我使用的工具是bower。其實NPM也可以管理,但是NPM並不是讀取第三方依賴原始的repository,而是讀取自己管理的一個repository,所以更新可能會慢點,並且它使用CommonJS的介面方便Node.js專案的開發,並不是針對純前端開發的專案;而bower是讀取原始的github repository,沒有更新延遲的問題,所有包都是針對純前端開發專案的。
要使用bower只需要簡單的三步:
- 安裝:npm install bower -g
- 在專案根目錄中建立配置檔案.bowerrc
- 在專案根目錄中建立依賴配置檔案components.json
我們首先來看看.bowerrc的內容:
{ "directory" : "components", "json" : "component.json", "endpoint" : "https://bower.herokuapp.com" }
其中directory指定了所有的依賴會被安裝到哪裡;json指定了依賴配置檔案的路徑;endpoint制定了依賴的repository的定址伺服器,你可以替換為自己的定址伺服器。
然後我們來看看components.json的內容:
{ "name": "Project Name", "version": "0.0.1", "dependencies": { "jquery": "latest", "underscore": "latest", "backbone": "latest", "jasmine-jquery": "latest", "jasmine-ajax": "git@github.com:pivotal/jasmine-ajax.git" } }
其中最重要的就是dependencies,它指定了所有前端開發依賴的包。所有bower包含的依賴都可以在這裡查到,對於bower沒有包含的依賴也可以直接指定github的repository,例如:"jasmine-ajax": "git@github.com:pivotal/jasmine-ajax.git"。
最後執行bower install就可以在components資料夾中看到所有第三方依賴的檔案了。但是bower有一個問題,就是它將所有github repository中的檔案都下載下來了,其中有許多是我們不需要的檔案。下面我們會將我們需要的檔案提取出來打包放到我們指定的目錄中。
原始檔編譯
這裡我使用的工具是grunt,他本身主要是基於Node.js的檔案操作包,其中有許多外掛可以讓我們完成js檔案的compile和compress、sass到css的轉換等等操作。要使用它需要先安裝命令列工具:npm install grunt-cli -g,然後在專案根目錄中建立檔案Gruntfile.js,這個檔案用於定義各種task,我們首先定義一個task將從bower下載的第三方依賴都打包到檔案app/js/lib.js中:
module.exports = function(grunt) { var dependencies = [ 'components/jquery/jquery.js', 'components/underscore/underscore.js', 'components/backbone/backbone.js']; grunt.initConfig({ concat: { js: { src: dependencies, dest: 'app/js/lib.js' } } }); grunt.loadNpmTasks('grunt-contrib-concat'); };
這裡的grunt-contrib-concat就是grunt的一個外掛,用於檔案的合併操作,我們已經在前面的package.json中引入了。js是task name;src指定了合併的原始檔地址;dest指定了合併的目標檔案。這樣當我們執行grunt concat:js後,所有的依賴檔案都會被合併為app/js/lib.js。這樣做的好處是我們可以控制每個依賴的引入順序,但是麻煩的是每次引入新的依賴都需要手動加入到dependencies陣列中。這個暫時沒有更好的解決方案,因為不是所有的包都在自己的components.js中宣告瞭main檔案,很多時候必須自己手動指定。
JavaScript檔案編譯完成以後就是CSS檔案,在現代的前端開發中,我們已經很少直接寫CSS檔案了,一般都使用SASS或者LESS。grunt也提供了這種支援,這裡我使用的是grunt-contrib-compass:
module.exports = function(grunt) { var sasses = 'sass'; grunt.initConfig({ compass: { development: { options: { sassDir: sasses, cssDir: 'app/css' } } } }); grunt.loadNpmTasks('grunt-contrib-compass'); };
然後執行grunt compass:development就可以完成CSS檔案的編譯了。
自動化測試
這裡我使用的自動化測試工具是Jasmine,它grunt中同樣有一個外掛:grunt-contrib-jasmine。下面我們來看看如何在Gruntfile.js中定義測試的task:
module.exports = function(grunt) { var sources = 'app/js/**/*.js', specs = 'spec/**/*Spec.js'; grunt.initConfig({ jasmine: { test: { src: [sources], options: { specs: specs, helpers: ['spec/helper/**/*.js'], vendor: 'app/js/lib.js' } } } }); grunt.loadNpmTasks('grunt-contrib-jasmine'); };
配置完成以後就可以執行grunt jasmine:test來跑測試,但問題是每次寫完程式碼都要手動執行一次非常麻煩,最好可以每次程式碼有更改都自動跑一次,讓我們可以更快的得到反饋。grunt的watch外掛就提供了這種支援:
module.exports = function(grunt) { var sources = 'app/js/**/*.js', specs = 'spec/**/*Spec.js'; grunt.initConfig({ jasmine: { test: { src: [sources], options: { specs: specs, helpers: ['spec/helper/**/*.js'], vendor: 'app/js/lib.js' } } }, watch: { test: { files: [sources, specs], tasks: ['jasmine:test'] } } }); grunt.loadNpmTasks('grunt-contrib-jasmine'); grunt.loadNpmTasks('grunt-contrib-watch'); };
files指定了需要監聽變動的檔案;tasks指定了修改後自動觸發的task。現在只要我們執行grunt watch:test,那麼有任何原始檔、測試檔案的改動,Jasmine測試都會自動執行了。有時候我們也希望測試的結果顯示在網頁上,便於我們做js的除錯。那麼可以將tasks:['jasmine:test']改為tasks: ['jasmine:test:build'],然後開啟根目錄下的_SpecRunner.html檔案,就可以在網頁中看到測試結果了,再加上一些Chrome的Livereload外掛,就可以不用重新整理實時的看到測試結果,效率非常之高。雖然grunt外掛中也有livereload,但是與grunt-contrib-watch無法很好的整合,所以我沒有使用這種方式。
CI Pipeline
由於我的專案是host在github上,所以我選擇travis-ci作為我的CI伺服器。要啟用travis-ci需要以下幾步:
- 在travis-ci中註冊一個賬號,獲取一個token;
- 在你的github專案的Settings–>Service Hooks中找到Travis,填入token並且啟用;
- 回到travis-ci,在Accounts–>Repositories中開啟你的專案的service hook
- Push一個.travis.yml到github,觸發第一次build。
- 修改package.json的scripts項,指定執行測試的命令
下面我們來看看如何配置.travis.yml:
language: node_js node_js: - "0.8" before_script: - npm install -g grunt-cli
由於我們的環境是基於Node.js搭建的,所以在language設定了nodejs;而**nodejs指定了Node.js的版本;before_script**指定了在測試執行前需要執行的命令,由於我們的指令碼都是基於grunt的,所以需要先安裝grunt的命令列包。
然後再修改package.json:
{ ⋯⋯ "scripts": { "test": "grunt jasmine:test" } ⋯⋯ }
將修改以後的package.jsonpush到github上,再次觸發一個新的build,你可以看到你之前錯誤的build已經綠了。
這裡還有一個小提示:如何讓build狀態顯示在專案的readme中?很簡單,只需要在README.md中加入以下程式碼就可以了:
[![Build Status](https://travis-ci.org/path/to/your_repository.png?branch=master)](http://travis-ci.org/path/to/your_repository)
到這裡基本的環境搭建就完成了,當然我們還可以使用grund的registerTask來定義一個任務序列,還可以加入template的編譯⋯⋯這些都可以通過grunt來靈活設定。最重要的是現在別人拿到一個專案的程式碼以後,可以通過一些命令來快速的搭建本地環境,方便的進行測試和開發,而且沒有依賴與後端的開發環境,只要定義好介面,前端開發可以完全獨立開了。雖然這其中還有很多問題沒有解決,例如:
- 如何讓第三方依賴自申明main檔案
- package.json與components.json其實有些重複
- Live Reload還需要Chrome外掛才能完成
- ⋯⋯
這正是由於現在前端開發環境還沒有後端開發的那種標準化,也正是挑戰和機遇之所在!
相關文章
- 「移動開發」iuap mobile玩轉前端自動化構建移動開發前端
- Java後端中的持續交付:如何構建從開發到上線的自動化流程Java後端
- 前端流程自動化前端
- 前端自動化:Node 命令列前端自動構建釋出系統前端命令列
- 如何構建一個高效的開發流程
- Jenkins自動化前端專案構建Jenkins前端
- 前端之路: 用github的webhooks實現專案自動化構建前端GithubWebHook
- 自動化構建映象:Packer
- 教你如何搭建一個自動化構建的部落格
- 前端開發:基於cypress的自動化實踐前端
- grunt搭建自動化的web前端開發環境Web前端開發環境
- CI Weekly #14 | 如何構建合適的 CI/CD 開發流程?
- 使用Gulp構建前端自動化解決方案前端
- 構建高效的自動化測試框架框架
- 如何透過資料開發治理實現資料流程的自動化和規範化?
- 前端開發自動化單元測試趨勢前端
- Webpack自動化構建實踐指南Web
- 淺談自動化構建之grunt
- 淺談自動化構建之gulp
- Grunt自動化構建環境搭建
- 【前端福利】用grunt搭建自動化的web前端開發環境-完整教程前端Web開發環境
- jenkins自動構建前端專案(window,vue)Jenkins前端Vue
- Jenkins敏捷開發 自動化構建工具Jenkins敏捷
- 前端自動化前端
- 建立嵌入式軟體開發的自動構建環境
- iOS 自動化釋出 Fastlane 本地構建 IPA 並分發iOSAST
- Docker 構建統一的前端開發環境Docker前端開發環境
- 分析阿里前端-自動化架構思路-react阿里前端架構React
- 學習前端自動化構建工具Gulp前端
- Android Jenkins自動化構建之路AndroidJenkins
- 利用fastlane進行專案的自動化構建AST
- 由webpack引發的前端自動化講解Web前端
- Web 前端開發日誌(四):構建現代化 Node 應用Web前端
- Vue 3與ESLint、Prettier:構建規範化的前端開發環境VueEsLint前端開發環境
- jenkins 自動化流程Jenkins
- 如何理解RPA機器人流程自動化機器人
- 客戶管理系統如何使流程自動化
- 如何使用CRM實現銷售流程自動化?