在前端工程化系列[02]-Grunt構(gòu)建工具的基本使用和前端工程化系列[03]-Grunt構(gòu)建工具的運(yùn)轉(zhuǎn)機(jī)制這兩篇文章中,我們對(duì)Grunt以及Grunt插件的使用已經(jīng)有了初步的認(rèn)識(shí),并探討了Grunt的主要組件以及它的運(yùn)轉(zhuǎn)機(jī)制,這篇文章是Grunt使用的進(jìn)階教程,主要輸出以下內(nèi)容:
? Grunt項(xiàng)目的自定義任務(wù)
? Grunt任務(wù)的描述和依賴
? Grunt多目標(biāo)任務(wù)和選項(xiàng)
? Grunt項(xiàng)目任務(wù)模板配置
? Grunt自動(dòng)化構(gòu)建和監(jiān)聽(tīng)
3.1 Grunt自定義任務(wù)
在使用Grunt的時(shí)候,可以先到Grunt官網(wǎng)的插件列表搜索是否有適合自己項(xiàng)目的Grunt插件,如果有那么建議直接使用,如果沒(méi)有那么開(kāi)發(fā)者可以嘗試自定義任務(wù)或者是自己創(chuàng)建對(duì)應(yīng)的插件。Grunt的插件其實(shí)就是一些封裝好的任務(wù)(Task),沒(méi)有什么稀奇的,Grunt支持自定義任務(wù),而且方式非常簡(jiǎn)單。
如果我們需要定義一個(gè)任務(wù),向控制臺(tái)里輸出字符串信息,那么在package.json文件、Gruntfile文件已經(jīng)創(chuàng)建且grunt本地依賴已安裝的前提下,如下編輯Gruntfile文件即可:
//包裝函數(shù)
module.exports = function (grunt) {
//(1)自定義任務(wù)(一)
//向控制臺(tái)輸出:hello 文頂頂
//第一個(gè)參數(shù):任務(wù)的名稱(Task)
//第二個(gè)參數(shù):具體的任務(wù)內(nèi)容
grunt.registerTask("hello",function () {
grunt.log.writeln("hello 文頂頂");
});
//(2)自定義任務(wù)(二)
grunt.registerTask("football",function () {
grunt.log.writeln("皇家馬德里: how are you!");
grunt.log.writeln("尤文圖斯: how old are you!");
});
};
終端輸入命令執(zhí)行任務(wù),可以單個(gè)執(zhí)行,也可以一起執(zhí)行,下面給出具體執(zhí)行情況
wendingding:02-Grunt_Test wendingding$ grunt hello
Running "hello" task
hello 文頂頂
Done.
wendingding:02-Grunt_Test wendingding$ grunt football
Running "football" task
皇家馬德里: how are you!
尤文圖斯: how old are you!
Done.
wendingding:02-Grunt_Test wendingding$ grunt hello football
Running "hello" task
hello 文頂頂
Running "football" task
皇家馬德里: how are you!
尤文圖斯: how old are you!
Done.
通過(guò)上面的代碼我們可以看到,自定義任務(wù)非常簡(jiǎn)單,只需要調(diào)用grunt對(duì)象的registerTask方法即可,其中第一個(gè)參數(shù)是Task的名稱,第二個(gè)參數(shù)是回調(diào)函數(shù)用來(lái)存放具體的任務(wù)(比如這里是打印輸出)。
在自定義任務(wù)中,我們用到了grunt.log.writeln函數(shù),這是Grunt提供的眾多內(nèi)置方法之一,作用是向控制臺(tái)輸出消息并換行。同類型的方法還有g(shù)runt.log.error()、grunt.log.subhead()等方法,大家可以到官網(wǎng)API文檔自行查看。
Grunt項(xiàng)目在具體使用的時(shí)候,通常是自定義Task + Grunt插件相結(jié)合的形式,我們來(lái)看下面這段代碼:
//包裝函數(shù)
module.exports = function (grunt) {
//(1)自定義任務(wù)(一) 任務(wù)名稱 hello
grunt.registerTask("hello",function () {
grunt.log.writeln("hello 文頂頂");
});
//(2)自定義任務(wù)(二) 任務(wù)名稱 football
grunt.registerTask("football",function () {
grunt.log.writeln("皇家馬德里: how are you!");
grunt.log.writeln("尤文圖斯: how old are you!");
});
//(2) 插件的處理
//使用步驟:
//[1] 先把對(duì)應(yīng)的插件下載和安裝到本地的項(xiàng)目中 $ npm install grunt-contrib-concat --save-dev
//[2] 對(duì)插件(任務(wù))進(jìn)行配置 grunt.initConfig
//[3] 加載對(duì)應(yīng)的插件 loadNpmTasks
//[4] 注冊(cè)任務(wù) grunt.registerTask
//[5] 通過(guò)grunt命令執(zhí)行任務(wù)
//配置插件相關(guān)信息
grunt.initConfig({
"concat":{
"dist":{
"src":["src/demo_one.js","src/demo_two.js","src/demo_three.js"],
"dest":"dist/index.js"
}
}
});
//加載插件
grunt.loadNpmTasks("grunt-contrib-concat");
//注冊(cè)任務(wù)(一):把hello \ football \ concat 這三個(gè)Task注冊(cè)為default的Task
//當(dāng)執(zhí)行$ grunt 或者是$ grunt default的時(shí)候,會(huì)順序執(zhí)行者三個(gè)任務(wù)!
grunt.registerTask("default",["hello","football","concat"]);
//注冊(cè)任務(wù)(二)
grunt.registerTask("customTask",["hello","football"]);
};
對(duì)于上面的Gruntfile文件,如果在終端輸入$ grunt或者$ grunt default 命令則依次執(zhí)行hello football和concat三個(gè)任務(wù),輸入$ grunt customTask則一次執(zhí)行hello football 自定義任務(wù)。
3.2 任務(wù)描述和依賴
設(shè)置任務(wù)描述
隨著項(xiàng)目復(fù)雜性的增加,Grunt任務(wù)也會(huì)越來(lái)越多,而任務(wù)(Task)的可用性、用途以及調(diào)用方法可能會(huì)變得難以追蹤。所幸,我們可以通過(guò)給任務(wù)設(shè)定相應(yīng)的描述信息來(lái)解決這些問(wèn)題。
要給任務(wù)設(shè)置描述信息非常簡(jiǎn)單,只需要在調(diào)用registerTask方法的時(shí)候多傳遞一個(gè)參數(shù)即可(作為第二個(gè)參數(shù)傳遞),我們可以把一個(gè)具體的字符串描述信息作為函數(shù)的參數(shù)傳遞。
這里,我們修改上面示例代碼中football任務(wù)部分的代碼,并任務(wù)設(shè)置描述信息。
grunt.registerTask("football","17-18賽季 歐冠八分之一決賽抽簽場(chǎng)景",function () {
grunt.log.writeln("皇家馬德里: how are you!");
grunt.log.writeln("尤文圖斯: how old are you!");
});
此時(shí),在終端中輸入$ grunt --help命令就能夠看到當(dāng)前Grunt項(xiàng)目中可用的Task,以及相應(yīng)的描述信息了,關(guān)鍵信息如下。
Available tasks
hello Custom task.
football 17-18賽季 歐冠八分之一決賽抽簽場(chǎng)景
concat Concatenate files. *
default Alias for "hello", "football", "concat" tasks.
customTask Alias for "hello", "football" tasks.
任務(wù)依賴
在復(fù)雜的Grunt工作流程中,很多任務(wù)之間往往存在依賴關(guān)系,比如js代碼的語(yǔ)法檢查和壓縮這兩個(gè)任務(wù),壓縮任務(wù)需要依賴于語(yǔ)法檢查任務(wù),它們?cè)趫?zhí)行的時(shí)候存在一定的先后關(guān)系,這種情況我們稱之為任務(wù)依賴。
我們可以在注冊(cè)任務(wù)的時(shí)候,刻意指定這種依賴關(guān)系,他們更多的是以一種特定的先后順序執(zhí)行如果是自定義任務(wù),也可以通過(guò)grunt.task.requires()方法來(lái)設(shè)定這種任務(wù)間的依賴關(guān)系。
module.exports = function (grunt) {
//注冊(cè)兩個(gè)自定義任務(wù)
/*
* 第一個(gè)參數(shù):Task的名稱
* 第二個(gè)參數(shù):任務(wù)的描述信息
* */
grunt.registerTask("hi","描述信息:這是一個(gè)打招呼的任務(wù)",function () {
grunt.log.ok("hi 文頂頂");
});
grunt.registerTask("hello","任務(wù)的描述次信息:這是一個(gè)簡(jiǎn)單問(wèn)候任務(wù)",function () {
//設(shè)置任務(wù)依賴:表明當(dāng)前的任務(wù)在執(zhí)行的時(shí)候需要依賴于另外一個(gè)任務(wù)
//必須先執(zhí)行hi這個(gè)任務(wù),才能執(zhí)行hello這個(gè)任務(wù)
grunt.task.requires("hi");
console.log("Nice to meet you!");
});
};
上面的代碼中定義了hi和hello兩個(gè)任務(wù),其中hello這個(gè)Task需要依賴于hi的執(zhí)行,如果直接執(zhí)行hello,那么會(huì)打印任務(wù)依賴的提示信息,具體的執(zhí)行情況如下。
wendingding:05-Grunt項(xiàng)目任務(wù)的描述和依賴 wendingding$ grunt hello
Running "hello" task
Warning: Required task "hi" must be run first. Use --force to continue.
Aborted due to warnings.
wendingding:05-Grunt項(xiàng)目任務(wù)的描述和依賴 wendingding$ grunt hi hello
Running "hi" task
>> hi 文頂頂
Running "hello" task
Nice to meet you!
Done.
3.3 Grunt多目標(biāo)任務(wù)和Options選項(xiàng)
理解多目標(biāo)Task
Grunt中的多目標(biāo)任務(wù)(multi-task)是相對(duì)于基本任務(wù)而言的,多目標(biāo)任務(wù)幾乎是Grunt中最復(fù)雜的概念。它的使用方式非常靈活,其設(shè)計(jì)的目的是可以在當(dāng)個(gè)項(xiàng)目中支持多個(gè)Targets目標(biāo)[可以認(rèn)為是多種配置]。當(dāng)任務(wù)在執(zhí)行的時(shí)候,可以一次性執(zhí)行全部的Target也可以指定某一特定的Target執(zhí)行。
module.exports = function (grunt) {
//(1) 配置Task,給Task設(shè)置多個(gè)Target
grunt.config("hello",
{
"targetA":{
"des":"Nice to meet you!"
},
"targetB":{
"des":"how are you?"
},
}
);
//(2) 自定義任務(wù) 任務(wù)的名稱為hello
//第一個(gè)參數(shù):Task名稱
//第二個(gè)參數(shù):任務(wù)的描述信息
//第三個(gè)參數(shù):具體要執(zhí)行的任務(wù)
grunt.registerMultiTask("hello","描述信息:打招呼",function () {
grunt.log.ok("hello 文頂頂");
grunt.log.writeln("this.target:",this.target);
grunt.log.writeln("this.data:",this.data);
});
};
代碼說(shuō)明
通過(guò)觀察可以發(fā)現(xiàn),我們通過(guò)grunt.registerMultiTask方法創(chuàng)建了支持多任務(wù)(Target)操作的自定義任務(wù)hello,主要任務(wù)就是輸出“hello 文頂頂”消息以及打印當(dāng)前的target和data值。然后通過(guò)grunt.config方法來(lái)給hello這個(gè)Task設(shè)定了兩個(gè)Target,分別是targetA和targetB。
在上面的代碼中,我們引用了this.target和this.data這兩個(gè)屬性,回調(diào)函數(shù)中的this指向的是當(dāng)前正在運(yùn)行的目標(biāo)對(duì)象。執(zhí)行targetA這個(gè)選項(xiàng)的時(shí)候,打印的this對(duì)象如下:
{ nameArgs: 'hello:targetA',
name: 'hello',
args: [],
flags: {},
async: [Function],
errorCount: [Getter],
requires: [Function: bound ],
requiresConfig: [Function],
options: [Function],
target: 'targetA',
data: { des: 'Nice to meet you!' },
files: [],
filesSrc: [Getter] }
目前為止,我們一直在談?wù)揟ask(任務(wù))和Target(目標(biāo)),大家可能懵逼了,不禁要問(wèn)它們之間到底是什么關(guān)系?
私以為可以簡(jiǎn)單的類比一下,假設(shè)現(xiàn)在有一個(gè)任務(wù)就是中午吃大餐,而具體吃什么大餐,可以靈活安排多個(gè)方案進(jìn)行選擇,比如方案A吃西餐,方案B吃中餐,方案C吃日本料理。等我們真正到了餐館要開(kāi)吃的時(shí)候,可以選擇方案A吃西餐或者是方案B吃中餐,甚至中餐、西餐和日本料理全端上桌也未嘗不可。
Task指的是整個(gè)任務(wù),在這個(gè)例子中就是要吃大餐,Target指的是任務(wù)中的某一種可行方案,也就是方案A、方案B和方案C,吃大餐這個(gè)Task中我們配置了三個(gè)Target。定義任務(wù)的目的是為了執(zhí)行,在執(zhí)行Task的時(shí)候,我們可以選擇執(zhí)行某個(gè)或某幾個(gè)指定的Target(目標(biāo)),這樣的處理方式無(wú)疑更強(qiáng)大而且操作起來(lái)更加的靈活。
多目標(biāo)任務(wù)的執(zhí)行
運(yùn)行多目標(biāo)Task的時(shí)候,有多種方式選擇。
① 讓Task按照指定的target運(yùn)行。$ grunt TaskName:targetName
② 讓Task把所有的target都運(yùn)行一次。$ grunt TaskName
下面列出示例代碼的具體執(zhí)行情況
wendingding:05-Grunt項(xiàng)目任務(wù)的描述和依賴 wendingding$ grunt hello
Running "hello:targetA" (hello) task
>> hello 文頂頂
this.target: targetA
this.data: { des: 'Nice to meet you!' }
Running "hello:targetB" (hello) task
>> hello 文頂頂
this.target: targetB
this.data: { des: 'how are you?' }
Done.
wendingding:05-Grunt項(xiàng)目任務(wù)的描述和依賴 wendingding$ grunt hello:targetA
Running "hello:targetA" (hello) task
>> hello 文頂頂
this.target: targetA
this.data: { des: 'Nice to meet you!' }
Done.
wendingding:05-Grunt項(xiàng)目任務(wù)的描述和依賴 wendingding$ grunt hello:targetB
Running "hello:targetB" (hello) task
>> hello 文頂頂
this.target: targetB
this.data: { des: 'how are you?' }
Done.
如果在Gruntfile文件中,調(diào)用了grunt.registerTask方法來(lái)注冊(cè)自定義任務(wù),那么可以通過(guò)TaskName:targetName的來(lái)方式直接指定任務(wù)的Target
//注冊(cè)任務(wù) [給hello起一個(gè)別名]
grunt.registerTask("helloTargetA",["hello:targetA"]);
在終端中,輸入$ grunt helloTargetA命令將會(huì)執(zhí)行hello這個(gè)Task中的targetA選項(xiàng)。
多目標(biāo)任務(wù)的Options選項(xiàng)
在對(duì)多目標(biāo)的任務(wù)進(jìn)行配置的時(shí)候,任何存儲(chǔ)在options選項(xiàng)下面的數(shù)據(jù)都會(huì)被特殊的處理。
下面列出一份Gruntfile文件中的核心代碼,并以多種方式執(zhí)行,通過(guò)這份代碼能夠幫助我們理解多目標(biāo)任務(wù)的Options選項(xiàng)配置。
//包裝函數(shù)
module.exports = function (grunt) {
//(1) 配置Task相關(guān)信息
/*
* 第一個(gè)參數(shù):Task的名稱
* 第二個(gè)參數(shù):任務(wù)的描述信息
* */
grunt.initConfig({
"hi": {
/*對(duì)整個(gè)任務(wù)中所有target的配置項(xiàng) 全局配置*/
options:{
"outPut":"array"
},
targetA:{
arrM:["targetA_1","targetA_2","targetA_3"]
},
targetB:{
options:{
"outPut":"json"
},
arrM:["targetB_1","targetB_2","targetB_3"]
},
targetC:{
arrM:["targetC_1","targetC_2","targetC_3"]
}
}
});
//(2) 自定義任務(wù) Task名稱為hi
//第一個(gè)參數(shù):Task名稱
//第二個(gè)參數(shù):任務(wù)的描述信息
//第三個(gè)參數(shù):具體要執(zhí)行的任務(wù)
grunt.registerMultiTask("hi","描述次信息:這是一個(gè)打招呼的任務(wù)",function () {
console.log("任務(wù)當(dāng)前執(zhí)行的target: "+this.target);
console.log("任務(wù)當(dāng)前執(zhí)行的target對(duì)應(yīng)的數(shù)據(jù): \n");
var objT = this.options();
if (objT.outPut === "array")
{
console.log("輸出數(shù)組:\n");
console.log(this.data.arrM);
}else if (objT.outPut === "json")
{
console.log("輸出JSON數(shù)據(jù):\n");
console.log(JSON.stringify(this.data.arrM));
}
});
//(1) 相關(guān)的概念 Task(任務(wù)-hi) | target(目標(biāo))
//(2) 任務(wù)的配置:任務(wù)中可以配置一個(gè)或者是多個(gè)目標(biāo) 調(diào)用config
//(3) 復(fù)合任務(wù)的執(zhí)行(多任務(wù)-多target)
// 001 grunt TaskName 把當(dāng)前Task下面所有的目標(biāo)操作都執(zhí)行一遍
// 002 grunt TaskName:targetName 執(zhí)行當(dāng)前Task下面的某一個(gè)指定的目標(biāo)
grunt.registerTask("default",["hi"]);
};
具體的執(zhí)行情況
wendingding:06-Grunt項(xiàng)目多任務(wù)和options wendingding$ grunt
Running "hi:targetA" (hi) task
任務(wù)當(dāng)前執(zhí)行的target: targetA
任務(wù)當(dāng)前執(zhí)行的target對(duì)應(yīng)的數(shù)據(jù):
輸出數(shù)組:
[ 'targetA_1', 'targetA_2', 'targetA_3' ]
Running "hi:targetB" (hi) task
任務(wù)當(dāng)前執(zhí)行的target: targetB
任務(wù)當(dāng)前執(zhí)行的target對(duì)應(yīng)的數(shù)據(jù):
輸出JSON數(shù)據(jù):
["targetB_1","targetB_2","targetB_3"]
Running "hi:targetC" (hi) task
任務(wù)當(dāng)前執(zhí)行的target: targetC
任務(wù)當(dāng)前執(zhí)行的target對(duì)應(yīng)的數(shù)據(jù):
輸出數(shù)組:
[ 'targetC_1', 'targetC_2', 'targetC_3' ]
Done
代碼說(shuō)明
上面的代碼中定義了一個(gè)多目標(biāo)任務(wù),Task的名稱為hi,該Task有三個(gè)target目標(biāo)選項(xiàng),分別是targetA、targetB和targetC。在任務(wù)配置相關(guān)代碼中,全局的options配置項(xiàng)中outPut屬性對(duì)應(yīng)的值為array,表示具體的目標(biāo)任務(wù)在執(zhí)行的時(shí)候以數(shù)組的形式輸出。
我們看到在targetB目標(biāo)中重寫了options選項(xiàng)中的outPut屬性為json,當(dāng)終端執(zhí)行$ grunt命令的時(shí)候,會(huì)依次執(zhí)行所有三個(gè)target目標(biāo)選項(xiàng),而targetA和targetC以數(shù)組格式來(lái)輸出內(nèi)容,targetB則以json格式來(lái)輸出內(nèi)容。
Grunt多目標(biāo)任務(wù)以及選項(xiàng)使得我們可以針對(duì)不同的應(yīng)用環(huán)境,以不同的方式來(lái)運(yùn)行同一個(gè)Task。可以利用這一點(diǎn),我們完全能夠定義Task為不同的構(gòu)建環(huán)境創(chuàng)建不同的輸出目標(biāo)。
說(shuō)明 ? this.options()方法用于獲取當(dāng)前正在執(zhí)行的目標(biāo)Task的options配置選項(xiàng)。
3.4 Grunt項(xiàng)目任務(wù)配置模板
Grunt項(xiàng)目中配置模板的簡(jiǎn)單使用
在Grunt項(xiàng)目中,我們可以使用<% %>分隔符的方式來(lái)指定模板,當(dāng)Task讀取自己配置信息的時(shí)候模板的具體內(nèi)容會(huì)自動(dòng)擴(kuò)展,且支持以遞歸的方式展開(kāi)。
在通過(guò)<%= ... %>在向模板綁定數(shù)據(jù)的時(shí)候,我們可以直接傳遞配置對(duì)象中的屬性或調(diào)用grunt提供的方法,模板中屬性的上下文就是當(dāng)前的配置對(duì)象。
下面,我們通過(guò)Gruntfile文件中的一段核心代碼來(lái)展現(xiàn)配置模板的使用情況。
module.exports = function (grunt) {
//(1) 創(chuàng)建并設(shè)置grunt的配置對(duì)象
//配置對(duì)象:該對(duì)象將作為參數(shù)傳遞給grunt.config.init方法
var configObj = {
concat: {
target: {
//src:["src/demo1.js","src/demo2.js"]
src: ['<%= srcPath %>demo1.js', '<%= srcPath %>demo2.js'],
//dest:["dist/2018_05_21_index.js"]
dest: '<%= targetPath %>',
},
},
srcPath:"src/",
destPath:"dist/",
targetPath:"<%= destPath %><%= grunt.template.today('yyyy_mm_dd_') %>index.js"
};
//(2) 調(diào)用init方法對(duì)任務(wù)(Task)進(jìn)行配置
// grunt.config.init 方法 === grunt.initConfig方法
grunt.config.init(configObj);
//(3) 加載concat插件
grunt.loadNpmTasks("grunt-contrib-concat");
//(4) 注冊(cè)Task
grunt.registerTask("default",["concat"]);
};
上面這段代碼對(duì)concat插件代碼合并Task進(jìn)行了配置,使用到了模板技術(shù)。該任務(wù)把src目錄下的demo1和demo2兩個(gè)js文件合并到dist目錄下并命名為2018_05_21_index.js文件。
Grunt項(xiàng)目中導(dǎo)入外部的數(shù)據(jù)
在向模板綁定數(shù)據(jù)的時(shí)候,常見(jiàn)的做法還會(huì)導(dǎo)入外部的數(shù)據(jù),并把導(dǎo)入的數(shù)據(jù)設(shè)置為配置對(duì)象的指定屬性值。比如在開(kāi)發(fā)中常常需要用到當(dāng)前Grunt項(xiàng)目的元信息,包括名稱、版本等,這些數(shù)據(jù)常通過(guò)調(diào)用grunt.file.readJSON方法加載package.json文件的方式獲取。下面給出代碼示例:
//包裝函數(shù)
module.exports = function (grunt) {
//設(shè)置(demoTask和concat)Task的配置信息
grunt.config.init({
//從package.json文件中讀取項(xiàng)目的元(基本)信息
pkg:grunt.file.readJSON("package.json"),
//demoTask的配置信息
demoTask :{
banner:"<%=pkg.name%> -- <%=pkg.version%>"
},
//concat的配置信息
concat:{
options:{
stripBanners:true,
banner:'/*項(xiàng)目名稱:<%=pkg.name%> 項(xiàng)目版本:<%=pkg.version%> 項(xiàng)目的作者:<%=pkg.author%> 更新時(shí)間:<%=grunt.template.today("yyyy-mm-dd")%>*/\n'
},
target:{
src:["src/demo1.js","src/demo2.js"],
dest:'dist/index.js'
}
}
});
//自定義Task 任務(wù)的名稱為demoTask
grunt.registerMultiTask("demoTask",function () {
console.log("執(zhí)行demo任務(wù)");
//表示調(diào)用config方法來(lái)讀取demoTask里面的banner屬性并輸出
console.log(grunt.config("demoTask.banner"));
});
//從node_modules目錄中加載concat插件
//注意:需要先把插件下載到本地 npm install grunt-contrib-concat --save-dev
grunt.loadNpmTasks("grunt-contrib-concat");
//注冊(cè)任務(wù)
grunt.registerTask("default",["demoTask","concat"]);
};
如果在終端輸入$ grunt命令執(zhí)行,那么demoTask任務(wù)將會(huì)輸出grunt_demo -- 1.0.0打印消息,而concat任務(wù)則把兩個(gè)js文件合并到dist目錄下面的index.js文件并添加注釋信息。
wendingding$ grunt
Running "demoTask:banner" (demoTask) task
執(zhí)行demo任務(wù)
grunt_demo -- 1.0.0
Running "concat:target" (concat) task
Done.
wendingding:07-Grunt項(xiàng)目模板配置 wendingding$ cat dist/index.js
/*項(xiàng)目名稱:grunt_demo 項(xiàng)目版本:1.0.0 項(xiàng)目的作者:文頂頂 更新時(shí)間:2018-05-21*/
console.log("demo1");
console.log("demo2");
說(shuō)明 ?grunt.file.readJSON方法用于加載JSON數(shù)據(jù),grunt.file.readYAML方法用于加載YAML數(shù)據(jù)。
3.5 Grunt自動(dòng)化構(gòu)建和監(jiān)聽(tīng)
到這里,基本上就可以說(shuō)已經(jīng)熟練掌握Grunt了。上文我們?cè)谶M(jìn)行代碼演示的時(shí)候,不論是自定義任務(wù)還是Grunt插件使用的講解都是片段性的,支離破碎的,Grunt作為一款自動(dòng)化構(gòu)建工具,自動(dòng)化這三個(gè)字到現(xiàn)在還沒(méi)有體現(xiàn)出來(lái)。
顧名思義,自動(dòng)化構(gòu)建的意思就是能夠監(jiān)聽(tīng)項(xiàng)目中指定的文件,當(dāng)這些文件發(fā)生改變后自動(dòng)的來(lái)執(zhí)行某些特定的任務(wù)。否則的話,每次修改文件后,都需要我們?cè)诮K端里面輸入對(duì)應(yīng)的命令來(lái)重新執(zhí)行,這頂多能算半自動(dòng)化是遠(yuǎn)遠(yuǎn)不夠的。
下面給出一份更全面些的Gruntfile文件,該文件中使用了幾款常用的Grunt插件(uglify、cssmin、concat等)來(lái)搭建自動(dòng)化構(gòu)建項(xiàng)目的工作流。點(diǎn)擊獲取演示代碼
//包裝函數(shù)
module.exports = function (grunt) {
// 項(xiàng)目配置信息
grunt.config.init({
pkg:grunt.file.readJSON("package.json"),
//代碼合并
concat:{
options:{
stripBanners:true,
banner:'/*項(xiàng)目名稱:<%=pkg.name%> 項(xiàng)目版本:<%=pkg.version%> 項(xiàng)目的作者:<%=pkg.author%>'
+' 更新時(shí)間:<%=grunt.template.today("yyyy-mm-dd")%>*/\n'
},
target:{
src:["src/demo1.js","src/demo2.js"],
dest:'dist/index.js'
}
},
//js代碼壓縮
uglify:{
target:{
src:"dist/index.js",
dest:"dist/index.min.js"
}
},
//css代碼壓縮
cssmin:{
target:{
src:"src/index.css",
dest:"dist/index.min.css"
}
},
//js語(yǔ)法檢查
jshint:{
target:['Gruntfile.js',"dist/index.js"],
options:{
jshintrc:".jshintrc"
}
},
//監(jiān)聽(tīng) 自動(dòng)構(gòu)建
watch:{
target:{
files:["src/*.js","src/*.css"],
//只要指定路徑的文件(js和css)發(fā)生了變化,就自動(dòng)執(zhí)行tasks中列出的任務(wù)
tasks:["concat","jshint","uglify","cssmin"]
}
}
});
//通過(guò)命令行安裝插件(省略...)
//從node_modules路徑加載插件
grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks("grunt-contrib-cssmin");
grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-watch");
//注冊(cè)任務(wù):在執(zhí)行$ grunt命令的時(shí)候依次執(zhí)行代碼的合并|檢查|壓縮等任務(wù)并開(kāi)啟監(jiān)聽(tīng)
grunt.registerTask("default",["concat","jshint","uglify","cssmin","watch"])
};
當(dāng)在終端輸入
$ grunt命令的時(shí)候,grunt會(huì)執(zhí)行以下任務(wù)① 合并src/demo1.js和src/demo2.js文件并命名為index.js保存到dist目錄。
② 按照既定的規(guī)則對(duì)Gruntfile.js和index.js文件來(lái)進(jìn)行語(yǔ)法檢查。
③ 壓縮index.js文件并命名為index.min.js保存在dist目錄。
④ 壓縮src/index.css文件并保存到dist/index.min.css。
⑤ 開(kāi)啟監(jiān)聽(tīng),如果src目錄下面的js文件或css文件被更改則重新構(gòu)建。
關(guān)于監(jiān)聽(tīng)插件grunt-contrib-watch的更多用法建議查看使用文檔
