本文是gulp的入門級介紹,主要內容包括什么是gulp,gulp與grunt有什么區別,gulp可以解決grunt存在的哪些問題,以及一個簡單的說明例子。
什么是gulp
gulp的官方定義非常簡潔:基於文件流的構建系統。這里強調了 streaming,也就是gulp與grunt的在構建流程上的主要區別。具體區別在哪里,后面會簡單介紹。
The streaming build system。

另一個grunt?
相信很多前端的同學對grunt都不陌生,grunt的出現可以說是前端的福音,之前很多需要人肉完成的重復工作,用了grunt,一個命令就搞定了。
說到這里,很多同學可能會比較疑問:既然有了grunt,那同樣定位於前端構建的gulp存在的意義是?從gulp的介紹來看,gulp正是為了解決前端同學在使用grunt過程中遇到的這樣那樣的問題而出現的。是哪些問題呢?在 http://slid.es/contra/gulp 這個slide里,提到了幾點,比如:
grunt存在的一些問題
1、插件職能不夠單一
2、插件完成了本不該由插件完成的事情(這個我有點迷糊,為什么說是 things don't need to be plugins?)
3、配置過於復雜
4、由於糟糕的流程控制導致的臨時文件/目錄
- Plugins do multiple things
- Want a banner? Use the javascript minifier
- Plugins do things that don't need to be plugins
- Need to run your tests? Use a plugin
- Grunt config format is a mess that tries to do everything
- Not idiomatic with "the node way"
- Headache of temp files/folders due to bad flow control
用grunt的方式構建
前面列舉了四點grunt使用過程中存在的問題,其中1、2點個人覺得略顯牽強,插件職能不夠單一,或者完成了不該由插件完成的事情,這個跟grunt其實關系並不大,更多的應該歸責於插件的作者(當然使用頻率最高的那部分插件的作者就是grunt團隊的兄弟)。
比較認同的是后面兩點:復雜的配置、糟糕的流程控制。
配置這個是否復雜就不說太多了,在這點上可能爭議會比較大。而糟糕的流程控制這點是被詬病較多的,尤其是在規模稍大的項目里面。下面這張簡圖是grunt目前的工作流程:讀文件、修改文件、寫文件——讀文件、修改文件、寫文件——。。。
問題顯而易見:
1、效率低下:頻繁的磁盤IO會使得構建效率變得低下
2、無法有效串聯:讀文件、修改文件、寫文件的循環,導致插件與插件之前的工作無法有效串聯起來。
備注:配圖來自上面提到的slide

舉個例子
比如項目下有個index.html、app.scss、app.js,而index.html里引用了app.css、app.js,如下所示。假設最終的目的是將編譯壓縮后的app.css、壓縮后的app.js 內聯到index.html里,同時要保留壓縮前的app.css、app.js源文件,那么過程可能如下:(不一定完全准確)
1、將index.html、app.js、編譯生成的app.css 拷貝到 dist/ 下
2、壓縮 app.js、app.css,並生成到臨時目錄 .tmp/ 下
3、將 .tmp/app.js、.tmp/app.css 內聯到 dist/index.html里
<html> <head> <link type="text/css" rel="stylesheet" href="app.css" /> </head> <body> <script src="app.js"></script> </body> </html>
用gulp的方式構建
從上面的構建流程可以看到,多次文件讀寫以及臨時目錄就這樣以一種難以避免的姿態出現了。在gulp作者的構想里,合理的構建流程應該是這樣的:讀取文件——修改文件——修改文件。。。——寫文件(配圖來自前面提到的slide)

按照這種設想,上面舉的例子用gulp重寫,過程應該是這樣
1、讀文件:讀取index.html、app.js、app.css(讀文件)
2、編譯、壓縮app.css,壓縮app.js(處理文件流)
3、將A、B內聯到index.html中(還是處理文件流)
4、寫文件:將最終生成地結果寫到 dist/ 目錄下 (修改后的index.html、編譯后的app.css、未修改過的app.js)
壓縮文件的簡單例子
1、首先全局安裝gulp命令行工具(相當於grunt-cli)
npm install -g gulp
2、然后,在項目下安裝gulp(相當於grunt)、gulp-uglify
npm install --save-dev gulp gulp-uglify
3、在項目根目錄下創建 gulpfile.js
var gulp = require('gulp'), uglify = require('gulp-uglify'); gulp.task('default', function(){ gulp.src('src/app.js') .pipe(uglify()) .pipe(gulp.dest('dist/')); });
4、運行gulp
gulp
還看到哪些不同
從上面的例子可以看到,gulp似乎跟grunt有點像(同樣是命令行工具與本地構建工具結合),但區別也是很明顯的。grunt的一切基於配置(配置即任務),而gulp則是code based workflow(其實到最后也是一堆配置,只不過可讀性上大大提高)。這里有更詳細的介紹,摘要如下。其中個人覺得比較重要的是第二、第五點。第五點已經講過了。
關於第二點,個人的理解是,我們使用gulp插件時,只需要理解插件本身依賴的那個庫的原始配置就可以了,而不是像grunt那樣,經常都是將配置包裝一層后再暴露給使用者,比如grunt-contrib-compass。盡管可能是為了讓插件之間的配置更加統一,但的確導致了額外的理解成本。
- With Gulp your build file is code, not config
- You use standard libraries to do things
- Plugins are simple and do one thing - most are a ~20 line function
- Tasks are executed with maximum concurrency
- I/O works the way you picture it
寫在后面
盡管gulp高舉取代grunt的旗幟,但還是需要客觀地看待問題。工具本身有它的適用場景,想要萬能的靈丹妙葯可能有點不現實。gulp相對還很年輕,還需要更多的檢驗,但個人挺看好的。除了grunt、gulp,百度的FIS也相當不錯,牆裂推薦。
關於更多gulp的內容,歡迎加群討論 372015911
一些鏈接:
gulp的github地址:https://github.com/gulpjs/gulp
gulp,The streaming build system:http://slid.es/contra/gulp
FIS官網:http://fis.baidu.com/
