gulp的簡單介紹
gulp是一個即grunt後出現的一個前端構建工具,跟grunt相比,gulp的API很少並且很簡單,使用nodejs中stream來讀取和操作數據,其速度比grunt更快,下面讓我們來學習一下如何使用gulp快速構建你的項目。
本文主要介紹
gulp的安裝和使用
gulp的API
gulp的常用插件
gulp的安裝和使用
1.全局安裝gulp
$ npm install --global gulp
2.作爲項目依賴安裝gulp
$ npm install --save-dev gulp
3.使用gulp
1.在你的文件目錄下面建立一個package.json和gulpfile.js的文件。
package.json:此文件被npm用於存儲項目的元數據,以便將此項目發佈爲npm模塊。你可以在此文件中列出項目依賴的gulp插件,放置於devDependencies配置字段內;
gulpfile:用來配置或定義任務(task)並加載gulp插件的。
2.安裝gulp插件
$ npm install --save-dev gulp-uglify
--save-dev和--save的區別
如果只寫上--save,gulp插件在package.json的dependencies裏面保存,而寫--save-dev 的話,gulp插件會保存在package.json的devDependencies,這裏有關於這兩個屬性的區別http://www.cnblogs.com/jes_sh...
安裝包的兩種方式
$ npm insatll
devDependencies和dependencies都會安裝
$ npm install --production
只安裝dependencies而不安裝devDependencies。
$ npm install packagename
那麼只會安裝dependencies,而不安裝devDependencies。
$ npm install packagename --dev
devDependencies和dependencies都會安裝
舉個例子
我們新建一個文件夾只有package.json文件,執行 會默認讀取package.json的
devDependencies和dependencies裏面的屬性,並且安裝devDependencies和dependencies下面的包。
如下所示,會安裝gulp和gulp-concat,然後還會讀取gulp和gulp-concat
裏面的dependencies裏面的包,在安裝gulp和gulp-concat所依賴的包,但是這個時候並不會安裝devDependencies裏面的包了
{
"name": "grunt_test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies":{
"gulp": "^3.9.1"
},
"devDependencies": {
"gulp-concat": "^2.6.0"
},
"author": "",
"license": "ISC"
}
$ gulp npm install --save stream-combiner2
{
"name": "application-name",
"version": "0.0.1",
"devDependencies": {
"del": "^2.2.1",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.0",
"gulp-load-plugins": "^1.2.4",
"gulp-uglify": "^1.5.4",
"pump": "^1.0.1"
},
"dependencies": {
"stream-combiner2": "^1.1.1"
}
}
3.編寫gulpfile.js
var gulp = require('gulp');
var uglify = require('gulp-uglify');
gulp.task('uglifyTask', function (cb) {
return gulp.src('www/**')
.pipe(uglify())
.pipe(gulp.dest('dest'));
})
4.運行task
$ gulp uglifyTask
執行上述命令,就會執行uglifyTask這個task,如果只輸入gulp 那麼會默認執行default這個任務;
如果gulpfile中沒有設置default這個任務,直接執行gulp,就會拋出以下錯誤
➜$ gulp
[22:40:37] Using gulpfile ~/WebstormProjects/gulp/gulpfile.js
[22:40:37] Task 'default' is not in your gulpfile
[22:40:37] Please check the documentation for proper gulpfile formatting
gulp的API
gulp.src(globs,option)
gulp.dest(path, options)
task(name, deps, fn)
gulp.watch(glob , opts, tasks) 或 gulp.watch(glob , opts, cb)
就這四個API是不是特別少,在介紹這些API之前先說一下gulp的工作方式,gulpfile.js充分利用了Node.js的 Streams(流) API ,首先獲取到需要的stream,然後可以通過stream的pipe(管道)方法把流導入到你想要的地方,比如Gulp的插件中,經過插件處理後的流又可以繼續導入到其他插件中,當然也可以把流寫入到文件中。
1.gulp.src(globs,option)
gulp.src就是輸出符合所提供的匹配模式(glob)或者匹配模式的數組(array of globs)的文件。 將返回一個流,可以通過管道pipe輸入別的gulp插件,內容不是原始的文件流,而是一個虛擬文件對象流(這個是看一篇介紹說的,具體理解不深),我們可以簡單理解爲讀取一個符合globs匹配的文件
globs是文件匹配模式的一個字符串或者一個數組,下面是常用文件匹配模式
* 匹配任意數量的字符,但不匹配 /
? 匹配單個字符,但不匹配 /
** 匹配任意數量的字符,包括 /,只要它是路徑中唯一的一部分
[pattern,pattern1] 匹配方括號中出現的字符中的任意一個,當方括號中第一個字符爲^或!時,則表示不匹配方括號中出現的其他字符中的任意一個,類似js正則表達式中的用法
! 在模式的開頭用於排除一個匹配模式所匹配的任何文件
下面以一系列例子來加深印象,我的目錄結構是這樣的
'www/*' 匹配 www/a.js www/js
'www/?.js' 匹配 www/a.js
'www/**/*.js' 匹配 www/所有二級目錄下的js
['www/**/*.js','src/**/*.js'] 匹配 www和src下面的所有的子級目錄下面的js文件;
['www/**/*.js','!www/*.js'] 匹配不包含www下面的a.js的所有其他的js文件;
option通過 glob-stream 所傳遞給 node-glob 的參數,除了 node-glob 和 glob-stream 所支持的參數外,gulp 增加了一些額外的選項參數:
1.options.buffer 類型: Boolean 默認值: true
那麼將會以 stream 方式返回 file.contents 而不是文件 buffer 的形式返回;
2.options.read 類型: Boolean 默認值: true
如果該項被設置爲 false, 那麼 file.contents 會返回空值(null),也就是並不會去讀取文件。
3.ptions.base 類型 string
修改 base的值 默認的base的值爲通配符開始出現之前那部分路徑,如果設置了base值,那麼將依照這個base值爲基準
return gulp.src('www/js/**/*.js') //假設匹配上的是www/js/module/a.js,那麼base是www/js
.pipe($.uglify())
.pipe(gulp.dest('dest')); //dest輸出的是 dest/module/a.js
return gulp.src('www/js/**/*.js',{base:'www'}) //設定了base,那麼base是www
.pipe($.uglify())
.pipe(gulp.dest('dest')); //dest輸出的是 dest/js/module/a.js
2.gulp.dest(path, options)
path:文件輸出的目錄,只能是目錄地址,如果包含文件名,那麼會把文件名也當做目錄的一部分建對應的路徑,path將替換gulp.src裏面的base生成對應的目錄存放文件。
gulp.task('uglifyTask', function (cb) {
return gulp.src('www/js/**/*.js',{base:'www'})
.pipe($.uglify())
.pipe($.rename({extname: '.min.js'}))
.pipe(gulp.dest('dest/uglfy.min.js'));
})
options,這個一般不用,這裏就不做介紹了,需要了解的可以去官方api進行了解;
3.task(name, deps, fn)
gulp.task 定義一個任務,name類型:string,這個任務的名稱;deps類型:array,這個任務依賴的其他任務;fn類型:function 任務的具體操作,有一個參數,是執行完的回調函數cb
這個方法比較簡單,這裏我主要講一下執行順序
/** 壓縮 **/
gulp.task('uglifyTask',['clean:dest'],function (cb) {
console.log('uglifyTask執行')
return gulp.src('www/js/**/*.js',{base:'www'})
.pipe($.uglify())
.pipe($.rename({extname: '.min.js'}))
.pipe(gulp.dest('dest/uglfy.min.js'));
})
/** 刪除 **/
gulp.task('clean:dest', function (cb) {
console.log('dest已經執行完畢')
del([
'dest/**/*'
])
})
$ gulp uglifyTask
上面代碼我們會認爲首先輸出‘dest已經執行完畢’,‘然後輸出uglifyTask執行’,結果我們去命令行輸出的結果是這個樣子滴
➜ gulp gulp uglifyTask
[00:10:54] Using gulpfile ~/WebstormProjects/gulp/gulpfile.js
[00:10:54] Starting 'clean:dest'...
dest已經執行完畢
➜ gulp
只輸出了dest已經執行完畢,這是爲什麼?
原來,默認的,task 將以最大的併發數執行,也就是說,gulp 會一次性運行所有的 task 並且不做任何等待。如果你想要創建一個序列化的 task 隊列,並以特定的順序執行,你需要在依賴的task裏面給出提示,告訴這個task已經執行完畢
提示的三種方式:
返回一個流
返回一個promise
執行回調函數;
瞭解這些後,上面的我們簡單改變一下,就可以讓clean執行完後,執行uglify的task;
gulp.task('clean:dest', function (cb) {
console.log('dest已經執行完畢')
return del([ //這是返回一個流
'dest/**/*'
])
// if (err) return cb(err); // 返回 error
// cb(); 執行回調函數
// return Promise.resolve('success'); 返回一個成功的promise
})
4.gulp.watch(glob , opts, tasks) 或 gulp.watch(glob , opts, cb)
gulp.watch 監視文件,並且可以在文件發生改動時候做一些事情。或者執行一些task
glob跟gulp.src的glob相同,這裏就不做介紹了,opts,這個也不經常用API上沒有詳細的介紹。我們主要講一下第三個參數爲tasks 或者 cb的
當第三個參數是tasks,監聽的文件改變的時候會依次執行tasks數組裏面的task,並且會返回一個EventEmitter,可以監聽EventEmitter的change事件,事件的回調函數會被傳入一個名爲 event 的對象。這個對象描述了所監控到的變動:
第三個參數是function,那麼監聽的文件改變的時候,會執行回調函數裏面的內容,同樣的回調函數也有一個event對象,包含以下屬性;
event.type
類型: String
發生的變動的類型:added, changed 或者 deleted。
event.path
類型: String
觸發了該事件的文件的路徑。
/** 監聽文件變化 tasks**/
var wachEvet=gulp.watch('www/js/**/*.js',['uglifyTask'])
wachEvet.on('change',function(event){
console.log(event.type+event.path);
})
/** fn **/
gulp.watch('www/js/**/*.js',function(event){
console.log(event.type+event.path);
})
執行watch 應該建立一個task,然後在命令行裏面輸入 gulp watch
gulp.task('watch',function(){
gulp.watch('www/js/**/*.js',function(event){
console.log(event.type+event.path);
})
})
gulp的常用插件
gulp的插件比較多,這裏我就簡單說幾個常用到的插件,別的插件我們可以通過這個網址去查詢https://www.npmjs.com/browse/...
1.gulp-load-plugins
作用:自動加載gulp插件
地址:https://www.npmjs.com/package/gulp-load-plugins
使用方法:
var $ = require('gulp-load-plugins')();
$.uglify()
// 同上面一樣
var uglify = require('gulp-uglify');
uglify()
2.gulp-rename
作用:重命名
地址:https://www.npmjs.com/package...
使用方法:
// 字符串形式
gulp.src("./src/main/text/hello.txt")
.pipe(rename("main/text/hello.js"))
.pipe(gulp.dest("./dist")); // ./dist/main/text/hello.js
// 方法
gulp.src("./src/**/hello.txt")
.pipe(rename(function (path) {
path.dirname += "/rname";
path.basename += "-goodbye";
path.extname = ".md"
}))
.pipe(gulp.dest("./dist")); //base=main/text ./dist/main/text/rname/hello-goodbye.md
// 對象
gulp.src("./src/main/text/hello.txt")
.pipe(rename({
dirname: "main/text/rname",
basename: "aloha",
prefix: "bonjour-",
suffix: "-hola",
extname: ".md"
}))
.pipe(gulp.dest("./dist")); // ./dist/main/text/rname/bonjour-aloha-hola.md
3.gulp-uglify
作用:壓縮js代碼,這個只是單純的壓縮,並不像grunt一樣還能改變名稱,所以要配合上面的rename使用
地址:https://www.npmjs.com/package...
使用方法:
gulp.task('uglifyTask',['clean:dest'],function (cb) {
return gulp.src('www/js/**/*.js',{base:'www'})
.pipe($.uglify())
.pipe($.rename({extname: '.min.js'}))
.pipe(gulp.dest('dest/uglfy.min.js'));
})
4.grunt-concat
作用:合併文件,下面實例會合並一個js,放在dest/concat/all.js
地址:https://www.npmjs.com/package...
使用方法:
gulp.task('concatTask', function (cb) {
return gulp.src('src/**/*.js')
.pipe($.concat('concat/all.js'))
.pipe(gulp.dest('dest'));
})
5.gulp-jshint
作用:語法檢查
地址:
使用方法:
gulp.task('jshint',function(){
return gulp.src('src/**/*.js')
.pipe($.jshint())
.pipe($.jshint.reporter('default')) //使用默認的錯誤提示
//.pipe(myReporter) 使用map-stream自定義錯誤信息
})
6.del
作用:刪除文件
地址:
使用方法:
gulp.task('clean:dest', function (cb) {
return del([
'dest/**/*'
])
})
7.stream-combiner2
作用:監聽流中的錯誤信息
使用方法:
var combiner = require('stream-combiner2');
var uglify = require('gulp-uglify');
var gulp = require('gulp');
gulp.task('test', function() {
var combined = combiner.obj([
gulp.src('bootstrap/js/*.js'),
uglify(),
gulp.dest('public/bootstrap')
]);
// 任何在上面的 stream 中發生的錯誤,都不會拋出,
// 而是會被監聽器捕獲
combined.on('error', console.error.bind(console));
return combined;
});
8.lazypipe
作用:提出流中的公共部分
網址:http://www.gulpjs.com.cn/docs...