Grunt入門(一)
什么是grunt
Grunt就和photoshop里面的插件一樣,它能夠幫我們自動完成一些反復重復的任務
ps插件里,我們經(jīng)常會用動自動切圖,自動導出切片這樣的工具。grunt里面,就可以使用自動編譯LESS、壓縮CSS、JS這樣的工具。
Grunt是一個平臺,沒有插件,Grunt什么事也不能做。它是提供了一個標準,任何插件都要去遵守的一個機制和規(guī)則。就和USB接口一樣,接在USB插口的,有可能是U盤,攝像頭這些完成不同功能的外設。
為什么要用Grunt
Grunt有一個龐大的生態(tài)圈, 里面有各種各樣現(xiàn)成的插件,可以滿足大部分的日常需要。無需額外開發(fā)。
快速安裝
- 安裝
Node.js - 使用
npm安裝Grunt npm install -g grunt-cli
Gruntfile.js與package.json
每一個Grunt項目都會帶上這兩個文件,接下來分別講解這兩個文件的用途。
package.json
npm命令運行時會讀取當前目錄的 package.json 文件和解釋這個文件,這個文件基于Packages/1.1 規(guī)范。
在這個文件里你可以定義你的應用名稱( name )、應用描述( description )、關(guān)鍵字( keywords )、版本號( version )、應用的配置項( config )、主頁( homepage )、作者( author )、資源倉庫地址( repository )、bug的提交地址( bugs ),授權(quán)方式( licenses )、目錄( directories )、應用入口文件( main )、命令行文件( bin )、應用依賴模塊( dependencies )、開發(fā)環(huán)境依賴模塊( devDependencies )、運行引擎( engines )和腳本( scripts )等。
下面是一份完整的package.json:
{
"name": "test",
"version": "0.1.0",
"description": "A testing package",
"author": "A messed author <messed@example.com>",
"dependencies": {
"express": "1.x.x",
"ejs": "0.4.2",
"redis": ">= 0.6.7"
},
"devDependencies": {
"vows": "0.5.x"
},
"main": "index",
"bin": {
"test": "./bin/test.js"
},
"scripts": {
"start": "node server.js",
"test": "vows test/*.js",
"preinstall": "./configure",
"install": "make && make install"
},
"engines": {
"node": "0.4.x"
}
}
當在項目的根目錄中運行npm install 時,npm會自動去安裝dependencies中定義的依賴包,在項目的根目錄中生成一個node_modules的文件夾,這個項目所需要的node庫就安裝在這個目錄下。
其余關(guān)于package.json的含義暫時不說。
Gruntfile.js
這個文件與package.json一樣,放在文件的根目錄下。
一個Gruntfile.js包含以下幾個部分:
- "wrapper" 函數(shù)
- 項目與任務配置
- 加載grunt插件和任務
- 自定義任務
一份完整的Gruntfile文件
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
});
// 加載包含 "uglify" 任務的插件。
grunt.loadNpmTasks('grunt-contrib-uglify');
// 默認被執(zhí)行的任務列表。
grunt.registerTask('default', ['uglify']);
};
"wrapper" 函數(shù)
每一份 Gruntfile (和grunt插件)都遵循同樣的格式,寫的Grunt代碼必須放在此函數(shù)內(nèi):
module.exports = function(grunt) {
// Do grunt-related things in here
};
項目與任務配置
大部分的Grunt任務都依賴某些配置數(shù)據(jù)項,這些數(shù)據(jù)被定義在一個Object內(nèi),作為參數(shù)傳遞給grunt.initConfig()方法。
在下面的案例中,
grunt.file.readJSON('package.json')將存儲在package.json文件中的JSON元數(shù)據(jù)引入到grunt config中。 由于<% %>模板字符串可以引用任意的配置屬性,因此可以通過這種方式來指定諸如文件路徑和文件列表類型的配置數(shù)據(jù),從而減少一些重復的工作。
你可以在這個配置對象中(傳遞給initConfig()方法的對象)存儲任意的數(shù)據(jù),只要它不與你任務配置所需的屬性沖突,否則會被 忽略。此外,由于這本身就是JavaScript,你不僅限于使用JSON;你可以在這里使用任意的有效的JS代碼。如果有必要,你甚至可以以編程的方式生成配置。
與大多數(shù)task一樣,grunt-contrib-uglify插件中的uglify任務要求它的配置被指定在一個同名屬性中。在這里有一個例子, 我們指定了一個banner選項(用于在文件頂部生成一個注釋),緊接著是一個單一的名為build的uglify目標,用于將一個js文件壓縮為一個目標文件。
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
}
}
});
當使用其他開發(fā)者開發(fā)的一些插件的時候,一般都會有說明這個配置格式,下面是從github中找的一個關(guān)于雪碧圖合并的插件:
// 自動雪碧圖
sprite: {
allslice: {
files: [
{
//啟用動態(tài)擴展
expand: true,
// css文件源的文件夾
cwd: 'css',
// 匹配規(guī)則
src: ['*.css'],
//導出css和sprite的路徑地址
dest: 'tmp/',
// 導出的css名
ext: '.sprite.css'
}
],
options: {
// 默認使用GM圖像處理引擎
'engine': 'gm',
// 默認使用二叉樹最優(yōu)排列算法
'algorithm': 'binary-tree',
// 給雪碧圖追加時間戳,默認不追加
'imagestamp':false,
// 給樣式文件追加時間戳,默認不追加
'cssstamp':true,
// 是否以時間戳為文件名生成新的雪碧圖文件,默認不生成新文件
'newsprite':true
}
}
}
加載grunt插件和任務
插件的安裝是定義在package.json中的dependencies對象里。如果我們已經(jīng)我們要在后期繼續(xù)添加插件,可以通過
npm install grunt-contrib-less --save-dev 的方式來安裝。
安裝好需要的grunt插件后,就需要把插件引入到項目中。比如我們要引入剛剛安裝好的grunt-contrib-less那我們就需要在gruntfile中使用如下方法:
grunt.loadNpmTasks('grunt-contrib-less');
自定義任務
grunt允許開發(fā)者自定義參數(shù)來指定執(zhí)行特定的任務。比如,當需要grunt-contrib-less這個插件來執(zhí)行l(wèi)ess編譯的時候,可以用grunt.registerTask()指定一個運行參數(shù)來自定義任務,如grunt.registerTask('less', ['less']); 。當執(zhí)行l(wèi)ess編譯時,只需要運行這樣的代碼就行grunt less 。grunt也提供默認的執(zhí)行方法, 如果只想運行grunt 命令,不加參數(shù)就能執(zhí)行l(wèi)ess編譯的話,我們也可以這樣來自定義任務grunt.registerTask('default', ['less']);。方法的第二個參數(shù)是一個數(shù)組,那就說明,一個參數(shù)是可以來執(zhí)行多個任務的。執(zhí)行的順序按照數(shù)組的順序串聯(lián)執(zhí)行。舉個例子,在less編譯完之后,想做一下圖片壓縮和JS壓縮,那我們可以這樣做:
grunt.registerTask('publish', ['less', 'imagemin', 'uglify']);
那么問題來了,是不是每一次新建一個項目都要去重寫這個gruntfile.js和package.json呢?答案肯定不是……
第二節(jié),再繼續(xù)講講腳手架(自動生成工具)yo與Grunt的關(guān)系和使用。