Gulp打包工具

前端打包工具有很多款,從早期雅虎的Ant到現(xiàn)在的Webpack,期間的迭代變化的差別之大,如同Java到JavaScript,除了名字有點(diǎn)一樣,幾乎就是兩門完全不同的語(yǔ)言。公司項(xiàng)目主要用Gulp和Webpack,本篇先整理一下Gulp。

如果你用過(guò)Grunt,可能覺(jué)得Gulp有點(diǎn)莫名其妙,Grunt前輩社區(qū)完善,插件成千上萬(wàn),弄出個(gè)Gulp干什么?我個(gè)人感覺(jué)在未來(lái)的前端開(kāi)發(fā)中一切都將是JS,因此即便是配置工具,Gulp用JS代碼實(shí)現(xiàn)的策略優(yōu)于Grunt的半JS半配置的策略。而且Gulp用流的方式進(jìn)行文件處理,通過(guò)管道將多個(gè)任務(wù)和操作連接在一起,全程只有一個(gè)IO過(guò)程,最后的結(jié)果直接寫入硬盤。因此打包流程更加清晰,沒(méi)有中間臨時(shí)文件,速度更快。注意,不要輕視“速度更快”這個(gè)評(píng)價(jià),打包的時(shí)間越短越好,快1秒也能提高前端工程師的效率,做前端的都懂的…

  • 安裝和執(zhí)行
  • 插件引入
  • task
  • 數(shù)據(jù)流
  • watch

安裝和執(zhí)行

安裝很簡(jiǎn)單:

npm install --global gulp

安裝之后,在工程目錄下新建一個(gè)名為gulpfile.js的文件:

var gulp = require('gulp');
gulp.task('default', function() {
    ……
});

這樣在目錄下執(zhí)行g(shù)ulp就能自動(dòng)執(zhí)行上面定義的default方法。

插件引入

作為一款流程的打包工具,社區(qū)豐富的插件庫(kù)是必不可少的。除了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ī)范,無(wú)論是前端頁(yè)面工程師,還是后端Node工程師都可以零基礎(chǔ)立馬上手。這可能也是Gulp能取代Grunt的一個(gè)原因。

task

引入插件后,就需要建立一個(gè)個(gè)子任務(wù)來(lái)執(zhí)行插件。task函數(shù)的原型:

gulp.task(name[, deps], fn)

第一個(gè)參數(shù)是task名。第二個(gè)參數(shù)可選,是個(gè)任務(wù)列表array,這些任務(wù)會(huì)在運(yùn)行當(dāng)前任務(wù)之前運(yùn)行,例如:

gulp.task('default', ['css', 'image', 'ejs', 'babel']);

需要注意的是,你需要確保array里的任務(wù)都在當(dāng)前任務(wù)開(kāi)始前被運(yùn)行完畢。如果array里的任務(wù)是同步方法,那就沒(méi)沒(méi)什么好擔(dān)心的,Gulp會(huì)確保順序依次執(zhí)行。但如果array里的任務(wù)是異步方法,需要確保是否使用了一個(gè)callback,或返回一個(gè)promise或stream。

第三個(gè)參數(shù)fn里定義了任務(wù)需要執(zhí)行的操作。

數(shù)據(jù)流
如果你熟悉Java,那么IO數(shù)據(jù)流這個(gè)策略應(yīng)該非常熟了。Gulp通過(guò)串聯(lián)起來(lái)的的小函數(shù)來(lái)傳遞數(shù)據(jù),這些函數(shù)會(huì)對(duì)數(shù)據(jù)進(jìn)行修改,然后把修改后的數(shù)據(jù)傳遞給下一個(gè)函數(shù)。src函數(shù)的原型:

gulp.src(globs[, options])

該函數(shù)將輸出匹配globs的文件。輸出的文件可以用pipe輸入到別的插件中,形成一串?dāng)?shù)據(jù)流。

第一個(gè)參數(shù)globs,可以是string也可以是array,是一些常用的正則表達(dá)式,例如:

js/sample.js    //精確匹配文件
js/*.js              //匹配js目錄下的所有js文件
js/**/*.js        //匹配js目錄及其子目錄下所有后綴為.js的文件
!js/sample.js   //從匹配結(jié)果中去除js/sample.js文件
 *.+(js|css)      //匹配根目錄下所有后綴為.js或者.css的文件

//例如:匹配js目錄及其子目錄下所有js文件,但需要去除后綴為.min.js的文件
gulp.src(['js/**/*.js', '!js/**/*.min.js'])

更多高級(jí)語(yǔ)法,請(qǐng)仔細(xì)閱讀node-glob語(yǔ)法。

第二個(gè)參數(shù)options可選,除了支持node-globglob-stream的參數(shù)外,還支持一些Gulp的額外的參數(shù)。例如:

options.buffer:如果設(shè)為false,將會(huì)以stream方式返回file.contents而不是文件buffer的形式。這在處理一些大文件的時(shí)候?qū)?huì)很有用。

options.read:如果設(shè)為false, 那么file.contents會(huì)返回null,這樣就不會(huì)去讀取文件

options.base:string型的值,將會(huì)被加在glob之前。例如下面兩段代碼唯一的區(qū)別是,上面這段沒(méi)有options.base,而下面這段加上了options.base,導(dǎo)致結(jié)果路徑有區(qū)別:

gulp.src('client/js/**/*.js') 
  .pipe(minify())
  .pipe(gulp.dest('build')); 
 //匹配client/js/somedir/somefile.js并且將base解析為client/js/,因此結(jié)果 寫入build/somedir/somefile.js

gulp.src('client/js/**/*.js', { base: 'client' })
  .pipe(minify())
  .pipe(gulp.dest('build'));
//結(jié)果寫入build/js/somedir/somefile.js

數(shù)據(jù)流的結(jié)果通過(guò)dest函數(shù)輸出,原型:

gulp.dest(path[, options])

第一個(gè)參數(shù)是文件被輸出的路徑,路徑是相對(duì)路徑,當(dāng)然相對(duì)路徑也可根據(jù)上面的options.base來(lái)計(jì)算。第二個(gè)參數(shù)options可選,具體可以參照Linux的文件系統(tǒng)操作命令:

options.cwd:默認(rèn)值process.cwd()。輸出目錄的 cwd 參數(shù),只在所給的輸出目錄是相對(duì)路徑時(shí)候有效。

options.mode:默認(rèn)值0777,用以定義所有在輸出目錄中所創(chuàng)建的目錄的權(quán)限。

看一個(gè)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文件對(duì)象流(stream或buffer),和普通的文件流(chunk)還是有區(qū)別的。因此在使用Gulp時(shí),如果pipe出現(xiàn)Streaming not supported??赡苁且?yàn)閭鹘oGulp及其插件的是普通文件流(例如Node里fs.createReadStream(‘a(chǎn)pp.js’).pipe(uglify()))??梢杂?a target="_blank" rel="nofollow">vinyl-source-stream轉(zhuǎn)換工具轉(zhuǎn)一下就行了。

watch

Gulp可以監(jiān)視文件的修改,功能類似于Jade里的-w參數(shù),當(dāng)文件有變動(dòng)時(shí),執(zhí)行回調(diào)函數(shù)。Watch有兩種原型:

gulp.watch(glob[, opts], tasks)
gulp.watch(glob[, opts, cb])

第一種原型:第一個(gè)參數(shù)glob用于指定哪些文件需要被監(jiān)視,語(yǔ)法參數(shù)數(shù)據(jù)流不贅述。第二個(gè)參數(shù)opts可選,參照gaze。第三個(gè)參數(shù)tasks用于指定當(dāng)被監(jiān)視的文件有改動(dòng)時(shí),執(zhí)行哪些task。watch函數(shù)始終會(huì)返回一個(gè)EventEmitter 來(lái)發(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ū)別是,第三個(gè)參數(shù)不是task數(shù)組,而是自定義回調(diào)函數(shù)?;卣{(diào)函數(shù)的參數(shù)是event對(duì)象,你可以從該參數(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...');
});

總結(jié)

技術(shù)總是在發(fā)展,從實(shí)際使用下來(lái)的經(jīng)驗(yàn)看,Gulp確實(shí)比Grunt更快,代碼更少更易讀。Gulp能火多久不清楚,目前來(lái)看,還是項(xiàng)目的一個(gè)比較理想的打包工具。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • gulpjs是一個(gè)前端構(gòu)建工具,與gruntjs相比,gulpjs無(wú)需寫一大堆繁雜的配置參數(shù),API也非常簡(jiǎn)單,學(xué)...
    依依玖玥閱讀 3,304評(píng)論 7 55
  • gulpjs是一個(gè)前端構(gòu)建工具,與gruntjs相比,gulpjs無(wú)需寫一大堆繁雜的配置參數(shù),API也非常簡(jiǎn)單,學(xué)...
    井皮皮閱讀 1,400評(píng)論 0 10
  • gulpjs是一個(gè)前端構(gòu)建工具,與gruntjs相比,gulpjs無(wú)需寫一大堆繁雜的配置參數(shù),API也非常簡(jiǎn)單,學(xué)...
    小裁縫sun閱讀 1,027評(píng)論 0 3
  • 1、gulp的安裝 首先確保你已經(jīng)正確安裝了nodejs環(huán)境。然后以全局方式安裝gulp: npm install...
    F_imok閱讀 2,483評(píng)論 1 11
  • 對(duì)網(wǎng)站資源進(jìn)行優(yōu)化,并使用不同瀏覽器測(cè)試并不是網(wǎng)站設(shè)計(jì)過(guò)程中最有意思的部分,但是這個(gè)過(guò)程中的很多重復(fù)的任務(wù)能夠使用...
    懵逼js閱讀 1,163評(píng)論 0 8

友情鏈接更多精彩內(nèi)容