Gulp與Grunt一樣,也是一個自動任務運行器。它充分借鑒了Unix操作系統的管道(pipe)思想,很多人認為,在操作上,它要比Grunt簡單。
[TOC]
## 安裝
Gulp需要全局安裝,然后再在項目的開發目錄中安裝為本地模塊。先進入項目目錄,運行下面的命令。
~~~
npm install -g gulp
npm install --save-dev gulp
~~~
除了安裝gulp以外,不同的任務還需要安裝不同的gulp插件模塊。舉例來說,下面代碼安裝了gulp-uglify模塊。
~~~
$ npm install --save-dev gulp-uglify
~~~
## gulpfile.js
項目根目錄中的gulpfile.js,是Gulp的配置文件。下面就是一個典型的gulpfile.js文件。
~~~
var gulp = require('gulp');
var uglify = require('gulp-uglify');
gulp.task('minify', function () {
gulp.src('js/app.js')
.pipe(uglify())
.pipe(gulp.dest('build'))
});
~~~
上面代碼中,gulpfile.js加載gulp和gulp-uglify模塊之后,使用gulp模塊的task方法指定任務minify。task方法有兩個參數,第一個是任務名,第二個是任務函數。在任務函數中,使用gulp模塊的src方法,指定所要處理的文件,然后使用pipe方法,將上一步的輸出轉為當前的輸入,進行鏈式處理。
task方法的回調函數使用了兩次pipe方法,也就是說做了兩種處理。第一種處理是使用gulp-uglify模塊,壓縮源碼;第二種處理是使用gulp模塊的dest方法,將上一步的輸出寫入本地文件,這里是build.js(代碼中省略了后綴名js)。
執行minify任務時,就在項目目錄中執行下面命令就可以了。
~~~
$ gulp minify
~~~
從上面的例子中可以看到,gulp充分使用了“管道”思想,就是一個數據流(stream):src方法讀入文件產生數據流,dest方法將數據流寫入文件,中間是一些中間步驟,每一步都對數據流進行一些處理。
下面是另一個數據流的例子。
~~~
gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(jshint())
.pipe(uglify())
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
});
~~~
上面代碼使用pipe命令,分別進行jshint、uglify、concat三步處理。
## gulp模塊的方法
### src()
gulp模塊的src方法,用于產生數據流。它的參數表示所要處理的文件,這些指定的文件會轉換成數據流。參數的寫法一般有以下幾種形式。
* js/app.js:指定確切的文件名。
* js/*.js:某個目錄所有后綴名為js的文件。
* js/**/*.js:某個目錄及其所有子目錄中的所有后綴名為js的文件。
* !js/app.js:除了js/app.js以外的所有文件。
* *.+(js|css):匹配項目根目錄下,所有后綴名為js或css的文件。
src方法的參數還可以是一個數組,用來指定多個成員。
~~~
gulp.src(['js/**/*.js', '!js/**/*.min.js'])
~~~
### dest()
dest方法將管道的輸出寫入文件,同時將這些輸出繼續輸出,所以可以依次調用多次dest方法,將輸出寫入多個目錄。如果有目錄不存在,將會被新建。
~~~
gulp.src('./client/templates/*.jade')
.pipe(jade())
.pipe(gulp.dest('./build/templates'))
.pipe(minify())
.pipe(gulp.dest('./build/minified_templates'));
~~~
dest方法還可以接受第二個參數,表示配置對象。
~~~
gulp.dest('build', {
cwd: './app',
mode: '0644'
})
~~~
配置對象有兩個字段。cwd字段指定寫入路徑的基準目錄,默認是當前目錄;mode字段指定寫入文件的權限,默認是0777。
### task()
task方法用于定義具體的任務。它的第一個參數是任務名,第二個參數是任務函數。下面是一個非常簡單的任務函數。
~~~
gulp.task('greet', function () {
console.log('Hello world!');
});
~~~
task方法還可以指定按順序運行的一組任務。
~~~
gulp.task('build', ['css', 'js', 'imgs']);
~~~
上面代碼先指定build任務,它由css、js、imgs三個任務所組成,task方法會并發執行這三個任務。注意,由于每個任務都是異步調用,所以沒有辦法保證js任務的開始運行的時間,正是css任務運行結束。
如果希望各個任務嚴格按次序運行,可以把前一個任務寫成后一個任務的依賴模塊。
~~~
gulp.task('css', ['greet'], function () {
// Deal with CSS here
});
~~~
上面代碼表明,css任務依賴greet任務,所以css一定會在greet運行完成后再運行。
task方法的回調函數,還可以接受一個函數作為參數,這對執行異步任務非常有用。
~~~
// 執行shell命令
var exec = require('child_process').exec;
gulp.task('jekyll', function(cb) {
// build Jekyll
exec('jekyll build', function(err) {
if (err) return cb(err); // return error
cb(); // finished task
});
});
~~~
如果一個任務的名字為default,就表明它是“默認任務”,在命令行直接輸入gulp命令,就會運行該任務。
~~~
gulp.task('default', function () {
// Your default task
});
// 或者
gulp.task('default', ['styles', 'jshint', 'watch']);
~~~
執行的時候,直接使用gulp,就會運行styles、jshint、watch三個任務。
### watch()
watch方法用于指定需要監視的文件。一旦這些文件發生變動,就運行指定任務。
~~~
gulp.task('watch', function () {
gulp.watch('templates/*.tmpl.html', ['build']);
});
~~~
上面代碼指定,一旦templates目錄中的模板文件發生變化,就運行build任務。
watch方法也可以用回調函數,代替指定的任務。
~~~
gulp.watch('templates/*.tmpl.html', function (event) {
console.log('Event type: ' + event.type);
console.log('Event path: ' + event.path);
});
~~~
另一種寫法是watch方法所監控的文件發生變化時(修改、增加、刪除文件),會觸發change事件。可以對change事件指定回調函數。
~~~
var watcher = gulp.watch('templates/*.tmpl.html', ['build']);
watcher.on('change', function (event) {
console.log('Event type: ' + event.type);
console.log('Event path: ' + event.path);
});
~~~
除了change事件,watch方法還可能觸發以下事件。
* end:回調函數運行完畢時觸發。
* error:發生錯誤時觸發。
* ready:當開始監聽文件時觸發。
* nomatch:沒有匹配的監聽文件時觸發。
watcher對象還包含其他一些方法。
* watcher.end():停止watcher對象,不會再調用任務或回調函數。
* watcher.files():返回watcher對象監視的文件。
* watcher.add(glob):增加所要監視的文件,它還可以附件第二個參數,表示回調函數。
* watcher.remove(filepath):從watcher對象中移走一個監視的文件。
## gulp-load-plugins模塊
一般情況下,gulpfile.js中的模塊需要一個個加載。
~~~
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat');
gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(uglify())
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
});
~~~
上面代碼中,除了gulp模塊以外,還加載另外三個模塊。
這種一一加載的寫法,比較麻煩。使用gulp-load-plugins模塊,可以加載package.json文件中所有的gulp模塊。上面的代碼用gulp-load-plugins模塊改寫,就是下面這樣。
~~~
var gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();
gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(plugins.jshint())
.pipe(plugins.jshint.reporter('default'))
.pipe(plugins.uglify())
.pipe(plugins.concat('app.js'))
.pipe(gulp.dest('build'));
});
~~~
上面代碼假設package.json文件包含以下內容。
~~~
{
"devDependencies": {
"gulp-concat": "~2.2.0",
"gulp-uglify": "~0.2.1",
"gulp-jshint": "~1.5.1",
"gulp": "~3.5.6"
}
}
~~~
## gulp-livereload模塊
gulp-livereload模塊用于自動刷新瀏覽器,反映出源碼的最新變化。它除了模塊以外,還需要在瀏覽器中安裝插件,用來配合源碼變化。
~~~
var gulp = require('gulp'),
less = require('gulp-less'),
livereload = require('gulp-livereload'),
watch = require('gulp-watch');
gulp.task('less', function() {
gulp.src('less/*.less')
.pipe(watch())
.pipe(less())
.pipe(gulp.dest('css'))
.pipe(livereload());
});
~~~
上面代碼監視less文件,一旦編譯完成,就自動刷新瀏覽器。
## 參考鏈接
* Callum Macrae,?[Building With Gulp](http://www.smashingmagazine.com/2014/06/11/building-with-gulp/)
- 第一章 導論
- 1.1 前言
- 1.2 為什么學習JavaScript?
- 1.3 JavaScript的歷史
- 第二章 基本語法
- 2.1 語法概述
- 2.2 數值
- 2.3 字符串
- 2.4 對象
- 2.5 數組
- 2.6 函數
- 2.7 運算符
- 2.8 數據類型轉換
- 2.9 錯誤處理機制
- 2.10 JavaScript 編程風格
- 第三章 標準庫
- 3.1 Object對象
- 3.2 Array 對象
- 3.3 包裝對象和Boolean對象
- 3.4 Number對象
- 3.5 String對象
- 3.6 Math對象
- 3.7 Date對象
- 3.8 RegExp對象
- 3.9 JSON對象
- 3.10 ArrayBuffer:類型化數組
- 第四章 面向對象編程
- 4.1 概述
- 4.2 封裝
- 4.3 繼承
- 4.4 模塊化編程
- 第五章 DOM
- 5.1 Node節點
- 5.2 document節點
- 5.3 Element對象
- 5.4 Text節點和DocumentFragment節點
- 5.5 Event對象
- 5.6 CSS操作
- 5.7 Mutation Observer
- 第六章 瀏覽器對象
- 6.1 瀏覽器的JavaScript引擎
- 6.2 定時器
- 6.3 window對象
- 6.4 history對象
- 6.5 Ajax
- 6.6 同域限制和window.postMessage方法
- 6.7 Web Storage:瀏覽器端數據儲存機制
- 6.8 IndexedDB:瀏覽器端數據庫
- 6.9 Web Notifications API
- 6.10 Performance API
- 6.11 移動設備API
- 第七章 HTML網頁的API
- 7.1 HTML網頁元素
- 7.2 Canvas API
- 7.3 SVG 圖像
- 7.4 表單
- 7.5 文件和二進制數據的操作
- 7.6 Web Worker
- 7.7 SSE:服務器發送事件
- 7.8 Page Visibility API
- 7.9 Fullscreen API:全屏操作
- 7.10 Web Speech
- 7.11 requestAnimationFrame
- 7.12 WebSocket
- 7.13 WebRTC
- 7.14 Web Components
- 第八章 開發工具
- 8.1 console對象
- 8.2 PhantomJS
- 8.3 Bower:客戶端庫管理工具
- 8.4 Grunt:任務自動管理工具
- 8.5 Gulp:任務自動管理工具
- 8.6 Browserify:瀏覽器加載Node.js模塊
- 8.7 RequireJS和AMD規范
- 8.8 Source Map
- 8.9 JavaScript 程序測試
- 第九章 JavaScript高級語法
- 9.1 Promise對象
- 9.2 有限狀態機
- 9.3 MVC框架與Backbone.js
- 9.4 嚴格模式
- 9.5 ECMAScript 6 介紹
- 附錄
- 10.1 JavaScript API列表
- 草稿一:函數庫
- 11.1 Underscore.js
- 11.2 Modernizr
- 11.3 Datejs
- 11.4 D3.js
- 11.5 設計模式
- 11.6 排序算法
- 草稿二:jQuery
- 12.1 jQuery概述
- 12.2 jQuery工具方法
- 12.3 jQuery插件開發
- 12.4 jQuery.Deferred對象
- 12.5 如何做到 jQuery-free?
- 草稿三:Node.js
- 13.1 Node.js 概述
- 13.2 CommonJS規范
- 13.3 package.json文件
- 13.4 npm模塊管理器
- 13.5 fs 模塊
- 13.6 Path模塊
- 13.7 process對象
- 13.8 Buffer對象
- 13.9 Events模塊
- 13.10 stream接口
- 13.11 Child Process模塊
- 13.12 Http模塊
- 13.13 assert 模塊
- 13.14 Cluster模塊
- 13.15 os模塊
- 13.16 Net模塊和DNS模塊
- 13.17 Express框架
- 13.18 Koa 框架