前言
以前一直使用Grunt作為前端自動化構(gòu)建工具,但始終覺得配置繁瑣尺迂,在之后一個項目中便決定使用更流行的構(gòu)建工具Gulp。因為Gulp使用node的stream
流進行文件和數(shù)據(jù)的讀取操作蹲盘,能減少I/O次數(shù),速度更快铃诬,主要API只有4個趣席,易上手醇蝴。下面我們來詳細學習一下Gulp這個工具吧。
安裝
確保你已經(jīng)安裝好了node環(huán)境霉涨,首先全局安裝gulp
npm install -g gulp
然后切換路徑到你項目的package.json
文件所在目錄下笙瑟,本地安裝gulp
npm install gulp --save-dev
為什么要安裝兩次呢癞志?因為全局安裝是方便你直接使用gulp命令,而本地安裝是因為之后需要安裝的gulp插件需要依賴gulp秉宿。主要是為了靈活,不用太糾結(jié)蘸鲸。
開始使用gulp
與grunt依賴一個Gruntfile.js
一樣窿锉,gulp也依賴一個主文件gulpfile.js
酌摇,這個文件主要定義了gulp的一些任務。我們可以進入項目package.json
文件所在目錄窑多,一般是根目錄洼滚,創(chuàng)建一個js文件并命名為gulpfile.js
埂息,然后寫入一個最簡單的任務,例如:
var gulp = require('gulp');
gulp.task('default',function(){
console.log('hello world');
});
這時我們的目錄結(jié)構(gòu)為
├── gulpfile.js
├── node_modules
│ └── gulp
└── package.json
在終端運行命令gulp
便可看到終端打印一句hello world
遥巴。你可以給任務一個特定的名字,然后運行特定任務铲掐,如gulp build
,如果沒有指定任務則自動執(zhí)行default
任務摆霉。
API介紹
搭建好工具后就要寫入一些任務為項目服務了,gulp的任務編寫就跟寫js一樣携栋,主要API只有4個gulp.src()婉支、gulp.dest()鸯隅、gulp.task()、gulp.watch()
磅摹,易于掌握,下面主要介紹一些易理解偏差的點饼灿,所以大家還是先看一遍官網(wǎng)的介紹。
1帝美、gulp.scr()
在gulp中使用的是node的stream流,首先獲取到stream庇忌,然后通過stream的pipe()方法把流導向你想要的地方舞箍,而gulp.src()方法就是獲取流的皆疹。但這個并不是原本的文件流疏橄,而是封裝過后的虛擬文件對象流(Vinyl files)捎迫,帶有原始文件的名稱表牢、路徑窄绒、內(nèi)容等信息。該方法的語法為:
gulp.src(globs [, options])
globs是文件匹配模式(類似正則匹配)崔兴,用來匹配文件路徑,也可以直接指定某個具體的文件路徑位谋,如果有多組匹配模式可以使用數(shù)組形式堰燎。options是一個可選參數(shù)。
下面介紹一下globs的匹配規(guī)則:
-
*
匹配文件路徑中的0個或多個字符,但不會匹配路徑分隔符翩腐,除非路徑分隔符出現(xiàn)在末尾。 -
**
匹配路徑中的0個或多個目錄及其子目錄何什,需要單獨出現(xiàn)处渣,即它左右不能有其他東西了泥畅。如果出現(xiàn)在末尾方椎,也能匹配文件钧嘶。 -
?
匹配文件路徑中的一個字符(不會匹配路徑分隔符)有决。 -
[...]
匹配方括號中出現(xiàn)的字符中的任意一個闸拿,當方括號中第一個字符為^
或!
時疮薇,則表示不匹配方括號中出現(xiàn)的其他字符中的任意一個胸墙,類似js正則表達式中的用法按咒。 -
!(pattern|pattern|pattern)
匹配與括號中給定的任一模式都不匹配的字符励七。 -
?(pattern|pattern|pattern)
匹配括號中給定的任一模式0次或1次吼野。 -
+(pattern|pattern|pattern)
匹配括號中給定的任一模式至少1次瞳步。 -
*(pattern|pattern|pattern)
匹配括號中給定的任一模式0次或多次嘀倒。 -
@(pattern|pattern|pattern)
匹配括號中給定的任一模式1次碳胳。
當有多組匹配模式時盗誊,可以使用數(shù)組
gulp.src(['static/**/*.js', 'static/**/*.css', 'static/**/*.html'])
使用數(shù)組的好處在于能使用!
進行排除某些模式,但注意!
不能為數(shù)組的第一個字符
gulp.src(['static/**/*.js', '!static/module/*.js'])
2质欲、gulp.dest()
gulp.dest()
方法是用來寫文件的树埠,語法如下:
gulp.dest(path [, options])
path是路徑參數(shù),options是可選參數(shù)嘶伟,一般用不到怎憋。
如果想用好這個方法,就要理解好文件傳入路徑與傳出路徑的關系九昧。gulp的工作流程是通過src()獲取指定路徑下的文件流绊袋,通過pipe()導到某些gulp插件中處理,完成后通過pipe()導到dest()中铸鹰,最后寫到指定的目錄下愤炸。
- 這里重要的一點是,gulp.dest()的路徑參數(shù)只能指定生成文件的目錄路徑名稱掉奄,不能指定生成文件的文件名稱,而文件名稱是由傳入的文件流名稱決定的凤薛。
var gulp = require('gulp');
gulp.src('script/jquery.js')
.pipe(gulp.dest('dist/foo.js'));
//最終生成的文件路徑為 dist/foo.js/jquery.js,而不是dist/foo.js
如果想改變文件名稱可以使用其他gulp插件完成姓建。
- 另一點是gulp.dest()生成的路徑是由
path
參數(shù)加上gulp.src()文件匹配路徑的通配符開始出現(xiàn)后的部分組成,舉例說明:
var gulp = require('gulp');
// 如果匹配到的文件是static/js/me/me.js
gulp.src('static/js/**/*.js')
// 由于通配符出現(xiàn)的部分是**/*.js缤苫,所以導出的文件路徑是dist/js/me/me.js
.pipe(gulp.dest('dist/js'));
再比如
gulp.src('script/avalon/avalon.js') //沒有通配符出現(xiàn)的情況
.pipe(gulp.dest('dist')); //最后生成的文件路徑為 dist/avalon.js
通過設置gulp.src()
的base
參數(shù)速兔,可以靈活的修改gulp.dest()
生成的路徑,如果沒有設置則base
參數(shù)默認是指傳入路徑匹配模式通配符出現(xiàn)前的部分活玲,比如:
gulp.src('app/src/**/*.css') //此時base的值為 app/src
所以上面的說法可以理解為涣狗,gulp.dest()
生成的路徑是path
參數(shù)替換傳入文件路徑的base
部分谍婉,修改base
參數(shù)就可以修改生成文件路徑,比如:
// 沒有配置base參數(shù)镀钓,此時默認的base路徑為script/lib
gulp.src('script/lib/*.js')
// 假設匹配到的文件為script/lib/jquery.js
.pipe(gulp.dest('build')); // 生成的文件路徑為 build/jquery.js
// 如果配置了base參數(shù)穗熬,此時base路徑為script
gulp.src('script/lib/*.js', {base:'script'})
//假設匹配到的文件為script/lib/jquery.js
.pipe(gulp.dest('build'));// 此時生成的文件路徑為 build/lib/jquery.js
-
gulp.dest()
把文件流寫入文件后,文件流還能導入其他插件繼續(xù)使用
3丁溅、gulp.task()
gulp.task()
是用來定義任務的唤蔗,內(nèi)部使用的是Orchestrator,一個以最大并發(fā)排列和運行任務和依賴的模塊窟赏,task的語法為:
gulp.task(name [, deps] fn)
name是定義的任務名妓柜,deps是任務依賴的其他任務,是一個數(shù)組的形式涯穷,定義的任務會在依賴的任務執(zhí)行完成后再執(zhí)行棍掐,如果沒有依賴任務可以省略,fn是任務具體執(zhí)行的操作拷况,該參數(shù)也是可選的作煌。
在gulp.task()
中執(zhí)行多個任務,可以通過依賴來完成蝠嘉,比如要執(zhí)行default
任務時最疆,還要執(zhí)行one、two蚤告、three
三個任務努酸,可以這樣寫
// 這樣one tow three三個任務都被執(zhí)行了
gulp.task('default', ['one', 'two', 'three'], function() {
// do something
})
如果任務相互間沒有依賴,則任務會按照你寫的順序執(zhí)行杜恰,如果有依賴則先執(zhí)行依賴的任務获诈。但如果某個依賴的任務是異步的,那gulp不會等待這個異步任務執(zhí)行完心褐,而會繼續(xù)執(zhí)行后面的任務舔涎。例如:
gulp.task('one',function(){
//one是一個異步執(zhí)行的任務
setTimeout(function(){
console.log('one is done')
},5000);
});
//two任務雖然依賴于one任務,但并不會等到one任務中的異步操作完成后再執(zhí)行
gulp.task('two',['one'],function(){
console.log('two is done');
});
最終的結(jié)果是先打印'two is done',然后再打印'one is done'逗爹。
那我們?nèi)绾螌崿F(xiàn)異步任務同步的功能呢亡嫌,請看另一篇文章《以同步的方式運行 Gulp 任務和任務中的步驟》。
4掘而、gulp.watch()
gulp.watch()
是用來監(jiān)聽文件變化的挟冠,這樣你就可以在開發(fā)中實時監(jiān)測文件的改動,然后自動做出相應的變化袍睡,比如壓縮知染,其語法為
gulp.watch(glob [, opts] task)
glob是文件的通配符模式,匹配文件路徑斑胜,opts是可配置參數(shù)控淡,一般不用嫌吠,task是監(jiān)聽變化后要執(zhí)行的任務,是一個數(shù)組掺炭。
gulp.task('uglify',function(){
//do something
});
gulp.task('reload',function(){
//do something
});
gulp.watch('js/**/*.js', ['uglify','reload']);
gulp.watch()
還有另一種形式
gulp.watch(glob [, opts] cb)
前兩個參數(shù)一樣辫诅,cb是回調(diào)函數(shù),監(jiān)聽的文件變化時會調(diào)用該方法竹伸,方法傳遞一個參數(shù)泥栖,該參數(shù)帶有文件變化的信息,type
屬性為變化的類型勋篓,可以是added
吧享,changed
,deleted
譬嚣;path
屬性為發(fā)生變化的文件的路徑
gulp.watch('js/**/*.js', function(event){
console.log(event.type); //變化類型 added為新增,deleted為刪除钢颂,changed為改變
console.log(event.path); //變化的文件的路徑
});
gulp常用插件
-
gulp-rename
重命名文件 -
gulp-sass
編譯scss文件 -
gulp-uglify
壓縮js文件 -
gulp-concat
合并文件,css和js -
gulp-htmlmin
壓縮html文件 -
gulp-autoprefixer
編譯廠商前綴 -
gulp-clean
刪除文件 -
gulp-rev
根據(jù)文件內(nèi)容生成hash值拜银,做靜態(tài)資源版本管理 -
gulp-rev-collector
替換html中的文件引用殊鞭,與gulp-rev
一起用 -
gulp.spritesmith
生成精靈圖 -
gulp-load-plugins
加載gulp插件,減少require的書寫 -
gulp-requirejs-optimize
合并打包requirejs的模塊引用 -
pump
使gulp的文件流往下傳遞尼桶,包括error操灿,如果有一個地方報錯,流的傳遞會停止 -
gulp-util
用來在命令中輸入?yún)?shù)泵督,給任務傳遞自定義的參數(shù) -
run-sequence
以同步的方式執(zhí)行異步任務
最后希望本文能幫助初學gulp的朋友理解gulp趾盐,參考自《前端構(gòu)建工具gulpjs的使用介紹及技巧》,謝謝小腊!