前言:之前一直說著做項目的時候要用gulp ,webpack,結果實習后一直用thinkphp之后就不怎么接觸,不會用gulp/webpack,總覺得不是一個合格的前端開發工作者呀!
最近做畢設用的是nodejs 的express,gulp使用的是nodejs中stream來讀取和操作數據,所以有nodejs的基礎的話,gulp非常容易理解
一,gulp的安裝
首先要確保安裝好了nodejs的環境,然后以全局的方式安裝gulp
npm install -g gulp
全局安裝后,還要在每個要使用gulp的項目中再安裝一次gulp,把目錄切換到安裝的目錄中
npm install gulp
如果想在安裝的時候把gulp寫進項目package.json文件的依賴中,則可以加上--save-dev:
npm install --save-dev gulp
二,gulp的使用
1,首先新建一個gulpfile.js的文件放在項目的目錄中
我們在文件中定義一個默認的任務
1 var gulp = require('gulp');
2 gulp.task('default',function(){
3 console.log('hello world');
4 });
此時我們的目錄結構是這樣子的:
|----gulpfile.js
|----node-modules
| |----gulp
|----package.json
2,運行gulp
windows下cmd中切換到項目目錄下
gulp 任務名
如果沒有指定任務名的話,就會執行default默認的任務
三,gulp的API
1,gulp.src()
在Gulp中,使用的是Nodejs中的stream(流),首先獲取到需要的stream,然后可以通過stream的pipe()
方法把流導入到你想要的地方,比如Gulp的插件中,經過插件處理后的流又可以繼續導入到其他插件中,當然也可以把流寫入到文件中。所以Gulp是以stream為媒介的,它不需要頻繁的生成臨時文件.
gulp.src()方法是用來獲取流的但要注意這個流里的內容不是原始的文件流,而是一個虛擬文件對象流(Vinyl files),這個虛擬文件對象中存儲著原始文件的路徑、文件名、內容等信息。用這個方法來讀取你需要操作的文件
語法如下:
gulp.src(globs[, options])
globs參數是文件匹配模式(類似正則表達式),用來匹配文件路徑(包括文件名),當然這里也可以直接指定某個具體的文件路徑。當有多個匹配模式時,該參數可以為一個數組。
options為可選參數。通常情況下我們不需要用到。
Gulp用到的glob的匹配規則以及一些文件匹配技巧。
*
匹配文件路徑中的0個或多個字符,但不會匹配路徑分隔符,除非路徑分隔符出現在末尾**
匹配路徑中的0個或多個目錄及其子目錄,需要單獨出現,即它左右不能有其他東西了。如果出現在末尾,也能匹配文件。?
匹配文件路徑中的一個字符(不會匹配路徑分隔符)[...]
匹配方括號中出現的字符中的任意一個,當方括號中第一個字符為^
或!
時,則表示不匹配方括號中出現的其他字符中的任意一個,類似js正則表達式中的用法!(pattern|pattern|pattern)
匹配任何與括號中給定的任一模式都不匹配的?(pattern|pattern|pattern)
匹配括號中給定的任一模式0次或1次,類似于js正則中的(pattern|pattern|pattern)?+(pattern|pattern|pattern)
匹配括號中給定的任一模式至少1次,類似于js正則中的(pattern|pattern|pattern)+*(pattern|pattern|pattern)
匹配括號中給定的任一模式0次或多次,類似于js正則中的(pattern|pattern|pattern)*@(pattern|pattern|pattern)
匹配括號中給定的任一模式1次,類似于js正則中的(pattern|pattern|pattern)
下面以一系列例子來加深理解
*
能匹配a.js
,x.y
,abc
,abc/
,但不能匹配a/b.js
*.*
能匹配a.js
,style.css
,a.b
,x.y
*/*/*.js
能匹配a/b/c.js
,x/y/z.js
,不能匹配a/b.js
,a/b/c/d.js
**
能匹配abc
,a/b.js
,a/b/c.js
,x/y/z
,x/y/z/a.b
,能用來匹配所有的目錄和文件**/*.js
能匹配foo.js
,a/foo.js
,a/b/foo.js
,a/b/c/foo.js
a/**/z
能匹配a/z
,a/b/z
,a/b/c/z
,a/d/g/h/j/k/z
a/**b/z
能匹配a/b/z
,a/sb/z
,但不能匹配a/x/sb/z
,因為只有單**
單獨出現才能匹配多級目錄?.js
能匹配a.js
,b.js
,c.js
a??
能匹配a.b
,abc
,但不能匹配ab/
,因為它不會匹配路徑分隔符[xyz].js
只能匹配x.js
,y.js
,z.js
,不會匹配xy.js
,xyz.js
等,整個中括號只代表一個字符[^xyz].js
能匹配a.js
,b.js
,c.js
等,不能匹配x.js
,y.js
,z.js
當有多種匹配模式時可以使用數組
gulp.src(['js/*.js','css/*.css','*.html'])
使用數組的方式還有一個好處就是可以很方便的使用排除模式,在數組中的單個匹配模式前加上!
即是排除模式,它會在匹配的結果中排除這個匹配,要注意一點的是不能在數組中的第一個元素中使用排除模式
1 gulp.src([*.js,'!b*.js']) //匹配所有js文件,但排除掉以b開頭的js文件 2 gulp.src(['!b*.js',*.js]) //不會排除任何文件,因為排除模式不能出現在數組的第一個元素中
此外,還可以使用展開模式。展開模式以花括號作為定界符,根據它里面的內容,會展開為多個模式,最后匹配的結果為所有展開的模式相加起來得到的結果。展開的例子如下:
a{b,c}d
會展開為abd
,acd
a{b,}c
會展開為abc
,ac
a{0..3}d
會展開為a0d
,a1d
,a2d
,a3d
a{b,c{d,e}f}g
會展開為abg
,acdfg
,acefg
a{b,c}d{e,f}g
會展開為abdeg
,acdeg
,abdeg
,abdfg
2,glup.dest()
gulp.dest()方法是用來寫文件的,其語法為:
gulp.dest(path[,options])
path為寫入文件的路徑
options為一個可選的參數對象,通常我們不需要用到
這個方法我們需要理解好傳入的路徑參數與最終生成的文件的關系。
gulp的使用流程一般是這樣子的:首先通過gulp.src()
方法獲取到我們想要處理的文件流,然后把文件流通過pipe方法導入到gulp的插件中,最后把經過插件處理后的流再通過pipe方法導入到gulp.dest()
中,gulp.dest()
方法則把流中的內容寫入到文件中,這里首先需要弄清楚的一點是,我們給gulp.dest()
傳入的路徑參數,只能用來指定要生成的文件的目錄,而不能指定生成文件的文件名,它生成文件的文件名使用的是導入到它的文件流自身的文件名,所以生成的文件名是由導入到它的文件流決定的,即使我們給它傳入一個帶有文件名的路徑參數,然后它也會把這個文件名當做是目錄名,例如:
1 var gulp = require('gulp');
3 gulp.src('script/jquery.js')
5 .pipe(gulp.dest('dist/foo.js'));
6
7 //最終生成的文件路徑為 dist/foo.js/jquery.js,而不是dist/foo.js
要想改變文件名,可以使用插件gulp-rename
gulp.dest(path)
生成的文件路徑是我們傳入的path參數后面再加上gulp.src()
中有通配符開始出現的那部分路徑。
1 var gulp = reruire('gulp'); //有通配符開始出現的那部分路徑為 **/*.js
2
3 gulp.src('script/**/*.js') .pipe(gulp.dest('dist')); //最后生成的文件路徑為 dist/**/*.js
4
5 //如果 **/*.js 匹配到的文件為 jquery/jquery.js ,則生成的文件路徑為 dist/jquery/jquery.js
3,gulp.task()
gulp.task
方法用來定義任務,內部使用的是Orchestrator,其語法為:
gulp.task(name[, deps], fn)
name 為任務名
deps 是當前定義的任務需要依賴的其他任務,為一個數組。當前定義的任務會在所有依賴的任務執行完畢后才開始執行。如果沒有依賴,則可省略這個參數
fn 為任務函數,我們把任務要執行的代碼都寫在里面。該參數也是可選的。
1 gulp.task('mytask', ['array', 'of', 'task', 'names'], function() {//定義一個有依賴的任務
2
3 // Do something
4
5 });
執行多個任務時怎么控制任務執行的順序
//只要執行default任務,就相當于把one,two,three這三個任務執行了
gulp.task('default',['one','two','three']);
如果任務相互之間沒有依賴,任務會按你書寫的順序來執行,如果有依賴的話則會先執行依賴的任務。
是如果某個任務所依賴的任務是異步的,就要注意了,gulp并不會等待那個所依賴的異步任務完成,而是會接著執行后續的任務。例如:
1 gulp.task('one',function(cb){ 2 var stream = gulp.src('client/**/*.js') 3 .pipe(dosomething()) //dosomething()中有某些異步操作 4 .pipe(gulp.dest('build')); 5 return stream; 6 }); 7 gulp.task('two',['one'],function(){ 8 console.log('two is done'); 9 });
上面的例子中我們執行two任務時,會先執行one任務,但不會去等待one任務中的異步操作完成后再執行two任務,而是緊接著執行two任務。所以two任務會在one任務中的異步操作完成之前就執行了。
那如果我們想等待異步任務中的異步操作完成后再執行后續的任務,該怎么做呢?
有三種方法可以實現:
第一:在異步操作完成后執行一個回調函數來通知gulp這個異步任務已經完成,這個回調函數就是任務函數的第一個參數。
1 gulp.task('one',function(cb){
2 //cb為任務函數提供的回調,用來通知任務已經完成
3 //one是一個異步執行的任務
4 setTimeout(function(){
5 console.log('one is done');
6 cb(); //執行回調,表示這個異步任務已經完成
7 },5000);
8 });
9 //這時two任務會在one任務中的異步操作完成后再執行
10 gulp.task('two',['one'],function(){
11 console.log('two is done');
12 });
第二:定義任務時返回一個流對象。適用于任務就是操作gulp.src獲取到的流的情況。
gulp.task('one',function(cb){
var stream = gulp.src('client/**/*.js')
.pipe(dosomething()) //dosomething()中有某些異步操作
.pipe(gulp.dest('build'));
return stream;
});
gulp.task('two',['one'],function(){
console.log('two is done');
});
第三:返回一個promise對象,例如
1 var Q = require('q'); //一個著名的異步處理的庫 https://github.com/kriskowal/q
2 gulp.task('one',function(cb){
3 var deferred = Q.defer();
4 // 做一些異步操作
5 setTimeout(function() {
6 deferred.resolve();
7 }, 5000);
8 return deferred.promise;
9 });
10
11 gulp.task('two',['one'],function(){
12 console.log('two is done');
13 });
4,gulp.watch()
gulp.watch()
用來監視文件的變化,當文件發生變化后,我們可以利用它來執行相應的任務,例如文件壓縮等。其語法為
gulp.watch(glob[, opts], tasks)
glob 為要監視的文件匹配模式,規則和用法與gulp.src()
方法中的glob
相同。
opts 為一個可選的配置對象,通常不需要用到
tasks 為文件變化后要執行的任務,為一個數組
1 gulp.task('uglify',function(){
2 //do something
3 });
4 gulp.task('reload',function(){
5 //do something
6 });
7 gulp.watch('js/**/*.js', ['uglify','reload']);
gulp.watch()
還有另外一種使用方式:
gulp.watch(glob[, opts, cb])
glob和opts參數與第一種用法相同
cb參數為一個函數。每當監視的文件發生變化時,就會調用這個函數,并且會給它傳入一個對象,該對象包含了文件變化的一些信息,type
屬性為變化的類型,可以是added
,changed
,deleted
;path
屬性為發生變化的文件的路徑
1 gulp.watch('js/**/*.js', function(event){ 2 console.log(event.type); //變化類型 added為新增,deleted為刪除,changed為改變 3 console.log(event.path); //變化的文件的路徑 4 });
博客轉載:http://www.cnblogs.com/2050/p/4198792.html
文章列表