前端打包工具有很多款鹏往,從早期雅虎的Ant到現(xiàn)在的Webpack,期間的迭代變化的差別之大缭保,如同Java到JavaScript,除了名字有點一樣帝雇,幾乎就是兩門完全不同的語言涮俄。公司項目主要用Gulp和Webpack,本篇先整理一下Gulp尸闸。
如果你用過Grunt彻亲,可能覺得Gulp有點莫名其妙孕锄,Grunt前輩社區(qū)完善,插件成千上萬苞尝,弄出個Gulp干什么畸肆?我個人感覺在未來的前端開發(fā)中一切都將是JS,因此即便是配置工具宙址,Gulp用JS代碼實現(xiàn)的策略優(yōu)于Grunt的半JS半配置的策略轴脐。而且Gulp用流的方式進行文件處理,通過管道將多個任務和操作連接在一起抡砂,全程只有一個IO過程大咱,最后的結果直接寫入硬盤。因此打包流程更加清晰注益,沒有中間臨時文件碴巾,速度更快。注意丑搔,不要輕視“速度更快”這個評價厦瓢,打包的時間越短越好,快1秒也能提高前端工程師的效率啤月,做前端的都懂的…
- 安裝和執(zhí)行
- 插件引入
- task
- 數(shù)據(jù)流
- watch
安裝和執(zhí)行
安裝很簡單:
npm install --global gulp
安裝之后煮仇,在工程目錄下新建一個名為gulpfile.js的文件:
var gulp = require('gulp');
gulp.task('default', function() {
……
});
這樣在目錄下執(zhí)行gulp就能自動執(zhí)行上面定義的default方法。
插件引入
作為一款流程的打包工具谎仲,社區(qū)豐富的插件庫是必不可少的浙垫。除了var gulp=require(‘gulp’);
是一定要引入的外,其他的插件根據(jù)需要自行引入强重。例如gulpfile.js的頭部可能是這樣的:
var gulp = require('gulp');
var del = require('del');
var less = require('gulp-less');
var base64 = require('gulp-base64');
var tpl2mod = require('gulp-tpl2mod');
var extReplace = require('gulp-ext-replace');
從上面代碼就能看出绞呈,Gulp完全遵守CommonJS的規(guī)范,無論是前端頁面工程師间景,還是后端Node工程師都可以零基礎立馬上手佃声。這可能也是Gulp能取代Grunt的一個原因。
task
引入插件后倘要,就需要建立一個個子任務來執(zhí)行插件圾亏。task函數(shù)的原型:
gulp.task(name[, deps], fn)
第一個參數(shù)是task名。第二個參數(shù)可選封拧,是個任務列表array志鹃,這些任務會在運行當前任務之前運行,例如:
gulp.task('default', ['css', 'image', 'ejs', 'babel']);
需要注意的是泽西,你需要確保array里的任務都在當前任務開始前被運行完畢曹铃。如果array里的任務是同步方法,那就沒沒什么好擔心的捧杉,Gulp會確保順序依次執(zhí)行陕见。但如果array里的任務是異步方法秘血,需要確保是否使用了一個callback,或返回一個promise或stream评甜。
第三個參數(shù)fn里定義了任務需要執(zhí)行的操作灰粮。
數(shù)據(jù)流
如果你熟悉Java,那么IO數(shù)據(jù)流這個策略應該非常熟了忍坷。Gulp通過串聯(lián)起來的的小函數(shù)來傳遞數(shù)據(jù)粘舟,這些函數(shù)會對數(shù)據(jù)進行修改,然后把修改后的數(shù)據(jù)傳遞給下一個函數(shù)佩研。src函數(shù)的原型:
gulp.src(globs[, options])
該函數(shù)將輸出匹配globs的文件柑肴。輸出的文件可以用pipe輸入到別的插件中,形成一串數(shù)據(jù)流旬薯。
第一個參數(shù)globs嘉抒,可以是string也可以是array,是一些常用的正則表達式袍暴,例如:
js/sample.js //精確匹配文件
js/*.js //匹配js目錄下的所有js文件
js/**/*.js //匹配js目錄及其子目錄下所有后綴為.js的文件
!js/sample.js //從匹配結果中去除js/sample.js文件
*.+(js|css) //匹配根目錄下所有后綴為.js或者.css的文件
//例如:匹配js目錄及其子目錄下所有js文件,但需要去除后綴為.min.js的文件
gulp.src(['js/**/*.js', '!js/**/*.min.js'])
更多高級語法隶症,請仔細閱讀node-glob語法政模。
第二個參數(shù)options可選,除了支持node-glob和glob-stream的參數(shù)外蚂会,還支持一些Gulp的額外的參數(shù)淋样。例如:
options.buffer:如果設為false,將會以stream方式返回file.contents而不是文件buffer的形式胁住。這在處理一些大文件的時候將會很有用趁猴。
options.read:如果設為false, 那么file.contents會返回null彪见,這樣就不會去讀取文件
options.base:string型的值儡司,將會被加在glob之前。例如下面兩段代碼唯一的區(qū)別是余指,上面這段沒有options.base捕犬,而下面這段加上了options.base,導致結果路徑有區(qū)別:
gulp.src('client/js/**/*.js')
.pipe(minify())
.pipe(gulp.dest('build'));
//匹配client/js/somedir/somefile.js并且將base解析為client/js/酵镜,因此結果 寫入build/somedir/somefile.js
gulp.src('client/js/**/*.js', { base: 'client' })
.pipe(minify())
.pipe(gulp.dest('build'));
//結果寫入build/js/somedir/somefile.js
數(shù)據(jù)流的結果通過dest函數(shù)輸出碉碉,原型:
gulp.dest(path[, options])
第一個參數(shù)是文件被輸出的路徑,路徑是相對路徑淮韭,當然相對路徑也可根據(jù)上面的options.base來計算垢粮。第二個參數(shù)options可選,具體可以參照Linux的文件系統(tǒng)操作命令:
options.cwd:默認值process.cwd()靠粪。輸出目錄的 cwd 參數(shù)蜡吧,只在所給的輸出目錄是相對路徑時候有效毫蚓。
options.mode:默認值0777,用以定義所有在輸出目錄中所創(chuàng)建的目錄的權限斩跌。
看一個Babel解碼ES6的例子:
gulp.task('babel', function () {
return gulp.src('./javascript/**/*.js')
.pipe(babel({
presets: [
'es2015',
'stage-0'
],
plugins: [
'transform-runtime',
'syntax-async-functions',
'transform-class-properties',
'transform-decorators-legacy'
]
}))
.pipe(gulp.dest('./js'));
});
最后绍些,Gulp及其插件使用的流是vinyl文件對象流(stream或buffer),和普通的文件流(chunk)還是有區(qū)別的耀鸦。因此在使用Gulp時柬批,如果pipe出現(xiàn)Streaming not supported⌒涠可能是因為傳給Gulp及其插件的是普通文件流(例如Node里fs.createReadStream(‘app.js’).pipe(uglify()))氮帐。可以用vinyl-source-stream轉換工具轉一下就行了洛姑。
watch
Gulp可以監(jiān)視文件的修改上沐,功能類似于Jade里的-w參數(shù),當文件有變動時楞艾,執(zhí)行回調函數(shù)参咙。Watch有兩種原型:
gulp.watch(glob[, opts], tasks)
gulp.watch(glob[, opts, cb])
第一種原型:第一個參數(shù)glob用于指定哪些文件需要被監(jiān)視,語法參數(shù)數(shù)據(jù)流不贅述硫眯。第二個參數(shù)opts可選蕴侧,參照gaze。第三個參數(shù)tasks用于指定當被監(jiān)視的文件有改動時两入,執(zhí)行哪些task净宵。watch函數(shù)始終會返回一個EventEmitter 來發(fā)射change 事件。例如:
var watcher = gulp.watch('js/**/*.js', ['uglify','reload']);
watcher.on('change', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});
第二種原型:和第一種的區(qū)別是裹纳,第三個參數(shù)不是task數(shù)組择葡,而是自定義回調函數(shù)√暄酰回調函數(shù)的參數(shù)是event對象敏储,你可以從該參數(shù)中獲取到event.type(被監(jiān)視的文件發(fā)生的變化類型added,changed朋鞍, deleted)和event.path(觸發(fā)該事件的文件的路徑)例如:
gulp.watch('js/**/*.js', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});
總結
技術總是在發(fā)展虹曙,從實際使用下來的經驗看,Gulp確實比Grunt更快番舆,代碼更少更易讀酝碳。Gulp能火多久不清楚,目前來看恨狈,還是項目的一個比較理想的打包工具疏哗。