定義:我的認爲,前端自動化就是便捷地將開發代碼迅速轉化爲發佈代碼的過程。javascript
意義:通常來講,開發代碼不會直接部署上線運行,小型項目倒問題不大,但對於大型項目來講,要考慮到服務器的壓力以及保密的等緣由,須要將代碼的體積最小化,減小請求數量,對代碼進行混淆和壓縮,若是手動完成這個過程,會比較繁瑣。css
主要用到的技術:Grunt(首先要安裝Node.js環境,安裝好Node.js環境至關於安裝好了npm,在項目建設過程當中就是用npm下載各個JS庫的)html
範例步驟:前端
1、先看看整個項目文件結構(假定咱們已經實現了src以及image文件夾下的全部內容)java
這個項目實現的功能是隨機顯示一個顏色做爲網頁背景,並隨機顯示一個0~100的數字。node
傳統的網頁項目只會有名爲src和image文件夾下的內容(忽略名爲concat的兩個文件夾以及文件夾下的內容,這兩個文件夾只是在生成過程當中的一個副產品^_^),真正部署時用到的是名爲dist以及image的文件夾。jquery
個人HTML文件是這樣的,引用了兩個js文件和一個css文件:npm
<!DOCTYPE html> <html> <head> <title>Grunt--前端自動化</title> <!-- build:css css/App.min.css --> <link rel="stylesheet" type="text/css" href="css/index.css"> <!-- endbuild --> </head> <body> <a>Grunt--前端自動化</a> <!-- build:js js/App.min.js --> <script type="text/javascript" src="node_modules/jquery/dist/jquery.min.js"></script> <script type="text/javascript" src="js/index.js"></script> <!-- endbuild --> </body> </html>
2、定義項目相關信息(package.json)json
{ "name": "App", "version": "1.0.0", "description": "Grunt Page", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Mandy","devDependencies": { "grunt": "^1.0.1", "grunt-contrib-clean": "^1.1.0", "grunt-contrib-concat": "^1.0.1", "grunt-contrib-copy": "^1.0.0", "grunt-contrib-csslint": "^2.0.0", "grunt-contrib-cssmin": "^2.2.0", "grunt-contrib-jshint": "^1.1.0", "grunt-contrib-uglify": "^3.0.1", "grunt-contrib-watch": "^1.0.0", "grunt-usemin": "^3.1.1", "jquery": "^3.2.1" }, "dependencies": { "grunt": "^1.0.1", "grunt-contrib-clean": "^1.1.0", "grunt-contrib-concat": "^1.0.1", "grunt-contrib-copy": "^1.0.0", "grunt-contrib-csslint": "^2.0.0", "grunt-contrib-cssmin": "^2.2.0", "grunt-contrib-jshint": "^1.1.0", "grunt-contrib-uglify": "^3.0.1", "grunt-contrib-watch": "^1.0.0", "grunt-usemin": "^3.1.1",
"jquery": "^3.2.1"
} }
package.json文件會描述這個npm包的全部相關信息,包括做者、簡介、包依賴、構建等信息,格式是嚴格的JSON格式。segmentfault
所展現的這個文件依次定義了npm包名、版本號、描述、入口文件、腳本說明對象、做者、只在開發時須要的依賴包、當前包所需的依賴包,固然這個文件還可有別的參數,具體能夠參考這裏或者這裏。
ps:之因此到處與npm相關,是由於基於grunt其實等於基於npm,而npm自己就是爲了開發者開發各類JS庫所誕生的「包管理工具」。
若是一開始項目沒有這個文件,能夠經過控制檯執行npm init,而後根據提示一步一步生成這個文件。
其中dependencies下的條目其實都不是手打的,實際上是能夠自動生成的,具體看下一步。
3、安裝依賴包(我所理解的JS庫,或許理解有誤,正確稱呼應爲依賴包)
安裝Grunt:控制檯執行npm install grunt --save-dev
後面這個--save-dev參數就是生成前面dependencies下內容的關鍵,若是是--save-dev,就會保存到devDependencies,若是是--save,就會保存到dependencies。
依此類推,安裝clean(清空文件夾)、concat(合併文件)、csslint(CSS語法檢查)、jshint(JS語法檢查)、cssmin(壓縮CSS)、uglify(混淆壓縮JS)、copy(複製文件)、useminPrepare(usemin的準備)、usemin(使用壓縮後的文件)、watch(檢測文件變化)。
npm install grunt-contrib-concat --save-dev
npm install grunt-contrib-csslint --save-dev
npm install grunt-contrib-cssmin --save-dev
npm install grunt-contrib-jshint --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-watch --save-dev
npm install grunt-usemin --save-dev
npm install grunt-contrib-copy --save-dev
npm install grunt-contrib-clean --save-dev
安裝完以後node_modules文件夾下就會出現截圖中所出現的依賴包了。
4、建立Gruntfile.js文件
module.exports = function(grunt){ //初始化grunt 配置 grunt.initConfig({ //獲取package.json的信息,也就是後面pkg變量的來源 pkg: grunt.file.readJSON('package.json'), // 各插件的配置信息 clean:{ src:"dist/" }, concat: { options:{ stripBanners:true, // 合併時容許輸出頭部信息 banner:'/*!<%= pkg.name %> - <%= pkg.version %>-'+'<%=grunt.template.today("yyyy-mm-dd") %> */' }, cssConcat:{ src:['src/css/*.css'], dest:'src/css/concat/<%= pkg.name %> - <%= pkg.version %>.css' // dest 是目的地輸出 }, jsConcat:{ src:[ 'node_modules/jquery/dist/jquery.min.js', 'src/js/index.js' ], dest:'src/js/concat/<%=pkg.name %> - <%= pkg.version %>.js' } }, csslint:{ options:{ csslintrc:'.csslint' }, build:['src/css/*.css'] }, jshint:{ options:{ jshintrc:'.jshint' }, build:['Gruntfile.js','src/js/*.js'] }, cssmin:{ options:{ stripBanners:true, // 合併時容許輸出頭部信息 banner:'/*!<%= pkg.name %> - <%= pkg.version %>-'+'<%=grunt.template.today("yyyy-mm-dd") %> */\n' }, build:{ src:'src/css/concat/<%=pkg.name %> - <%=pkg.version %>.css',// 壓縮是要壓縮合並了的 dest:'dist/css/<%= pkg.name %>.min.css' // dest 是目的地輸出 } }, uglify:{ options:{ stripBanners:true, // 合併時容許輸出頭部信息 banner:'/*!<%= pkg.name %> - <%= pkg.version %>-'+'<%=grunt.template.today("yyyy-mm-dd") %> */\n' }, build:{ src:'src/js/concat/<%=pkg.name %> - <%=pkg.version %>.js',// 壓縮是要壓縮合並了的 dest:'dist/js/<%= pkg.name %>.min.js' // dest 是目的地輸出 } }, copy:{ html:{ src:'src/index.html', dest:'dist/index.html' } }, useminPrepare:{ html:'index.html', options:{ dest:'dist' } }, usemin:{ html:['dist/index.html'], js:['dist/js/20170711 - 1.0.0.min.js'], css:['dist/css/20170711 - 1.0.0.min.css'] }, //watch自動化 watch:{ build:{ files:['src/js/*.js','src/css/*.css'], tasks:['concat','cssmin','uglify'], options:{spawn:false} } } }); // 告訴grunt咱們將使用插件 grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-csslint'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-usemin'); // 告訴grunt當咱們在終端輸入grunt時須要作些什麼 // 先進行語法檢查,若是沒有問題,再合併,再壓縮 grunt.registerTask('default', [ 'clean', 'concat', // 'csslint', // 'jshint', 'cssmin', 'uglify', 'copy', 'useminPrepare', 'usemin', 'watch' ] ); };
這個文件的存在是爲了定義當咱們在控制檯執行grunt的時候所要執行的操做。
initConfig是針對各個功能模塊的具體配置
loadNpmTasks是加載完成任務所需的模塊
registerTask是定義一個任務的執行過程(固然它不只僅只能這樣作,還能夠有更多功能和更多寫法,暫且這樣認爲吧)
5、執行
在控制檯中執行grunt命令,執行到如下效果時,說明代碼已經生成完畢了。
此時咱們能夠看到dist文件夾出如今了項目中,接下來咱們就只須要將dist文件夾和image文件夾拷貝到服務器上就能夠運行了。
生成後的項目只依賴於一個css文件和一個js文件(image文件夾其實我並無用到),而打開這兩個文件,咱們會發現css和js代碼都已經被壓縮成了一行。
HTML文件也變成了這樣:
<!DOCTYPE html> <html> <head> <title>Grunt--前端自動化</title> <link rel="stylesheet" href="css/App.min.css"> </head> <body> <a>Grunt--前端自動化</a> <script src="js/App.min.js"></script> </body> </html>
本來依賴的兩個js也自動合併成了一個js —— 這裏要隆重地說一說這個卡住我很久的問題!!!
一開始個人HTML並無變化,說明usemin並無起到效果?因而我爲了解決這個問題找了不少資料,期間查找無果擱置了一段時間。
這幾天才知道,原來是HTML文件中相應的JS或者CSS引用應該用<!-- build:js js/App.min.js --><!-- endbuild -->和<!-- build:css css/App.min.css --><!-- endbuild -->這樣的一個註釋括起來,以後usemin才能夠正常運做。
其實官方文檔已經提到過這個,可是因爲是用英文Blocks來描述的,半天反應不過來是指這樣的東西。。
沒留意裏面貼出的代碼段,也沒想到竟然一個註釋都能有這樣的功能。。