寫在前面
特別注意:如果覺得本文不夠詳盡,強烈建議去看 Grunt 英文官網 的教程,因為 中文版 的對註釋做了部分翻譯,不如不翻譯(容易被翻譯誤導)
- Grunt 是什麼?
Grunt 是自動構建工具,類似的東西還有 Ant、Buildy、Gmake 等等,更多的信息請查看 [黯羽輕揚:JS 自動化](/articles/js 自動化/)
- Grunt 有什麼用?
自動構建工具能把自動化工具整合起來,以任務的形式管理,所以 Grunt 官網的副標題是 The JavaScript Task Runner。
簡單解釋一下,構建項目 -> 模塊化開發 -> 復用 -> 測試 -> 調試 -> 驗證 -> 發布 -> 版本控制,這整個流程中需要用很多自動化工具,比如 Require、QUnit、JSHint、Uglify 等等。幾乎每次修改源碼都需要手動把某些工具按特定的順序 run again。。。
有了 Grunt 這樣的自動構建工具後就可以簡化 run again 的操作,寫好配置文件之後用命令行運行自定義任務即可,甚至可以配合 grunt-contrib-watch 插件監聽文件修改,自動運行任務
- Grunt 哪裡好?
-
火:Twitter、JQuery、Adobe、Mozilla 等等都在用 Grunt
-
插件多:目前(2015.5.22)已經有 4560 個 Grunt 插件了,包括常用的 JSHint、Require、Sass 等等,大大地夠用,實在不行還可以自己寫插件
-
好用:配置文件比較簡單,插件文檔齊全(npm 官網提供統一管理)
一.安裝 grunt
- 安裝 NodeJS
Windows 直接去http://nodejs.org/下載安裝包就好了,自帶 npm
其它平台的 安裝教程
裝好之後命令行輸入 node -v 測試一下
- 安裝 npm
命令行輸入 npm -v 測試一下,如果出錯的話,自己想辦法去裝 npm
- 安裝 Grunt-CLI(命令行工具 Command Line Interface)
命令行輸入 npm install -g grunt-cli 等待安裝完成即可
二.配置文件
需要兩個配置文件:
-
package.json:用於 Nodejs 包管理,聲明項目依賴模塊(grunt 以及 grunt 插件)
-
Gruntfile.js:Grunt 配置文件,用來定義任務,可以叫 Gruntfile.js 或者 Gruntfile.coffee
注意:package.json 和 Gruntfile.js 都要放在項目的根目錄下,與項目的源代碼一起提交
說白了,學 Grunt 就是學怎麼寫配置文件
三.package.json
一般格式如下:
{
"name": "項目名稱",
"version": "項目版本號",
"description": "項目描述",
"author": "項目創建者",
"license": "項目版權",
"devDependencies": {
// 項目依賴插件
}
}
例如一個小項目的 package.json:
{
"name": "world",
"version": "0.4.0",
"devDependencies": {
"grunt": "~0.4.2",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-jshint": "~0.6.3",
"grunt-contrib-uglify": "~0.2.2",
"grunt-contrib-watch": "^0.6.1"
}
}
寫好 package.json 後,命令行 cd 進來,執行 npm install,下載剛才聲明的各個依賴項,會被放在當前目錄下的 node_modules 文件夾里
需要添加依賴項的時候直接 npm install grunt-contrib-XXX --save-dev 就可以了,能夠自動更新 package.json 的內容
注意:
-
不能有註釋,否則 npm install 解析失敗(無論是哪種形式的註釋,無論放在文件首尾部分還是其它。。都不行)
-
version 必須是 X.X.X 形式,X.X 報錯
其實 version 的格式有複雜的標準,請查看http://semver.org/
- 命令行輸入 npm install grunt-contrib-XXX --save-dev 這樣的命令可以自動更新 package.json
最後一個依賴模塊 grunt-contrib-watch 就是這樣添進去的
- 版本號前面的~和^是什麼意思?
沒看到有資料解釋這個,但我們可以猜:^表示會去找最新版本,而表示指定版本(和 git 的 HEAD^ 與 HEADn 可能一樣。。當然,只是猜測)
一般都用~指定具體版本,因為可能存在插件兼容性以及穩定性問題
P.S.如果知道靠譜的解釋的話請告訴我,謝謝
- 自動生成 package.json
命令行輸入 npm init 根據命令行提示一步一步完成,實測不好用,建議手寫,或者寫一份常用的模版,強行復用
三.Gruntfile.js
一般格式如下:
module.exports = function(grunt){
// 1. 定義任務
grunt.initConfig({
// 1. 讀取 package.json
pkg: grunt.file.readJSON('package.json'),
// 2. 初始化各個任務的配置對象
task1: {
options: {
// 設置配置選項
},
build: {
// 設置輸入輸出路徑等等
}
},
task2: {
// ...
}
});
// 2. 加載插件
grunt.loadNpmTasks('Grunt 插件名');
// 3. 註冊任務
grunt.registerTask('default',['Grunt 任務']);
grunt.registerTask('mytask',['task1', 'task3']);
};
例如一個小項目的 package.json:
module.exports = function(grunt) {
// 1. 定義任務
grunt.initConfig({
// 1. 讀取 package.json
pkg: grunt.file.readJSON("package.json"),
// 2. 初始化各個任務的配置對象
// 合併文件
concat: {
options: {
// 防止合併出錯(上一個文件尾部少了分號)
separator: ";",
// 頂部信息(需要自帶註釋格式,不自動註釋,也不自動換行)
banner: "/*<%= pkg.name %>_<%= pkg.version %> " +
// *注意*:yyyy-mm-dd 要加引號,表示字符串參數
"<%= grunt.template.today('yyyy-mm-dd') %>*/\r\n\r\n",
// 底部信息
footer: "\r\n\r\n/* author: http://ayqy.net/ */"
},
build: {
src: ["src/w.js", "src/Const.js", "src/Item.js", "src/Map.js", "src/Util.js", "src/Core.js"],
dest: "build/<%= pkg.name %>.js"
}
},
// 代碼檢查
jshint: {
options: {
eqeqeq: true, // 要求===
trailing: true, // 要求尾部無空格
//unused: true, // 要求警告沒用到的變量(模塊化代碼會報錯)
forin: true, // 要求 for-in 必須有 hasOwnProp 過濾
curly: true // 要求花括號
},
files: ["Gruntfile.js", "src/*.js"]
},
// 代碼瘦身
uglify: {
options: {
// 不混淆變量名
mangle: false,
// 輸出壓縮率,可選的值有 false(不輸出信息),gzip
report: "min",
// 頂部信息(需要自帶註釋格式,不自動註釋,也不自動換行)
banner: "/*<%= pkg.name %>_<%= pkg.version %> " +
"<%= grunt.template.today('yyyy-mm-dd') %>*/\r\n\r\n",
// 底部信息
footer: "\r\n\r\n/* author: http://ayqy.net/ */"
},
build: {
files: {
// <%= concat.dist.dest %>表示 uglify 會自動瘦身 concat 任務中生成的文件
"build/<%= pkg.name %>.min.js": ["<%= concat.build.dest %>"]
}
}
},
// 監聽文件變動,自動執行任務
watch: {
files: ["<%= jshint.files %>"],
tasks: ["default"]
}
});
// 2. 加載插件
grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks("grunt-contrib-watch");
// 3. 註冊任務
grunt.registerTask("default", ["jshint", "concat", "uglify"]); // 默認任務
grunt.registerTask("check", ["jshint"]); // 自定義任務:代碼檢查
};
寫好 Gruntfile.js 後不需要執行 num install 之類的命令,直接用 grunt TaskName 執行對應的任務即可,比如:grunt 執行 default 任務,grunt jshint 執行代碼檢查,grunt mytask 按順序執行一連串的任務等等
如果有多個 target 的話可以用 grunt TaskName*:(英文半角冒號)*TargetName 執行指定的 target,在註冊任務的時候也可以用 TaskName:TargetName 指定 target
P.S.至於 target 是什麼,請往下看,配置 Gruntfile.js 可能有點麻煩,不過好在只用配置一次,以後直接用就可以了,可能對某些細節還不太理解,請務必看完下面的注意部分
注意:
- dist 和 build 到底用哪個?
常見的有 options-dist 和 options-build 兩種,都可以用,因為名字無所謂
只有 options 是有所謂的,比如我們可以這樣搞:
concat: {
options: {
separator: ";"
},
xx: {
src: "src/*.js",
dest: "<%= pkg.name %>.js"
}
}
當然還可以這樣搞:
concat: {
options: {
separator: ";"
},
xx: {
src: "src/*.js",
dest: "<%= pkg.name %>.js"
},
xxx: {
src: "src/*.js",
dest: "<%= pkg.name %>.js"
}
}
然後執行 grunt concat,會依次執行 xx 和 xxx,所以如果只有一個 target(xx 和 xxx 都叫 target)的話,用 build 和 dist 沒什麼區別,因為不需要語義區分
如果有多個 target,最好取一些語義友好的名字
P.S.個人更傾向於 build,當然,名字不重要,所以某些教程里甚至出現了 bar、foo 之類的,讓人費解
- 關於 options
上面的例子說明 grunt 只認 options(注意:少 1 個 s 都不行喲~),名字不是 options 的都一律當作 target 來執行
前面例子里都是 target 級的 options,其實也可以有 task 級的 options,可以對 task 下所有的 target 起作用,當然,不知道這個也沒關係,多寫點代碼而已
-
註冊同名任務會造成死遞歸
grunt.registerTask("concat", ["concat"]); -
可以給任務取別名
grunt.registerTask("check", ["jshint"]); // 自定義任務:代碼檢查 -
更多的例子
如果需要更多的例子幫助理解,建議自己寫個小項目,慢慢測試
如果實在沒多少時間,請查看 博客園:grunt 使用小記之 uglify:最全的 uglify 使用 DEMO
四.在線資源
- 不知道哪個插件能滿足需求,穩定,好用
http://www.gruntjs.net/plugins
鏈接頁面給出了 30 天內下載量 top100 的插件,附有功能簡介、最後更新時間等等,點擊即可跳轉至對應的 npm 官網插件主頁。此外還支持搜索,非常方便
- 不知道 XX 插件有哪些配置選項
鏈接頁面是 npm 官網,在搜索框里填插件名即可,例如 grunt-contrib-watch
插件主頁提供了詳細的配置說明以及例子,比如 watch 的配置選項:
最簡單的用法:
watch: {
files: ['**/*'],
tasks: ['jshint']
}
或者複雜的:
watch: {
sass: {
// We watch and compile sass files as normal but don't live reload here
files: ['src/sass/*.sass'],
tasks: ['sass']
},
livereload: {
// Here we watch the files the sass task will compile to
// These files are sent to the live reload server after sass compiles to them
options: { livereload: true },
files: ['dest/**/*']
}
}
3. Grunt API
鏈接頁面有 Grunt 的所有 API,比如 grunt.log、grunt.initConfig 等等等等,看到新東西就去查吧
參考資料
-
W3CPlus:Grunt 教程——初涉 Grunt:比大多數入門教程好很多
-
Grunt 中文官網:不推薦
-
Grunt 英文官網:強烈推薦
-
博客園:【grunt 整合版】30 分鐘學會使用 grunt 打包前端代碼:如果耐得住寂寞可以看這個。。
暫無評論,快來發表你的看法吧