Gulp是基于流的自動化構(gòu)建工具,它不僅能對網(wǎng)站資源進(jìn)行優(yōu)化,而且在開發(fā)過程中能避免很多重復(fù)的工作,比如對相關(guān)文件的操作,還有自動監(jiān)視一些文件的變化等功能。
基本的常用API(gulp v3.X)
-
gulp.src(globs[, options])
輸出符合所提供的匹配模式或者匹配模式的數(shù)組的文件。 將返回一個stream文件流它可以被 piped 到別的插件中。
glob 相當(dāng)于文件的路徑,或者文件路徑數(shù)組。 gulp.dest(path[, options])
// 把上一步處理的數(shù)據(jù)輸出到指定的目錄path中,如果某文件夾不存在,將會自動創(chuàng)建它。-
gulp.task(name[, deps], fn)
例子:
gulp.task('mytask', ['array', 'of', 'task', 'names'], function() { // 做一些事 });
異步、同步、規(guī)定執(zhí)行順序執(zhí)行任務(wù)
-
異步執(zhí)行任務(wù)
const gulp = require('gulp'); // 壓縮js代碼 gulp.task('js', function () { return gulp.src('src/js/*.js') // 匹配參數(shù)內(nèi)的文件,并且將文件讀到gulp內(nèi)存中 .pipe(concat('bundle.js')) // 合并文件代碼 .pipe(gulp.dest('dist/js/')) // 輸出文件到指定目錄 .pipe(uglify()) // 壓縮當(dāng)前的js文件 .pipe(rename({ // 重命名文件 suffix: '.min' })) .pipe(gulp.dest('dist/js/')) })// 壓縮css代碼 gulp.task('css', function () { return gulp.src('src/css/*.css') .pipe(concat('bundle.css')) .pipe(cleanCss()) // 壓縮css文件 .pipe(gulp.dest('dist/css/')) })// 執(zhí)行數(shù)組內(nèi)的任務(wù) gulp.task('default', ['js', 'css'])
當(dāng)運行命令 gulp 后,我們發(fā)現(xiàn)輸出的是
[11:31:43] Using gulpfile E:\練習(xí)\Gulp\4-12\gulpfile.js
[11:31:43] Starting 'css'...
[11:31:43] Starting 'js'...
[11:31:44] Finished 'js' after 72 ms
[11:31:44] Finished 'css' after 70 ms
[11:31:44] Finished 'default' after 33 μs
可以看到此時的任務(wù)是異步執(zhí)行的,應(yīng)用官方的一句話就是
默認(rèn)的,task 將以最大的并發(fā)數(shù)執(zhí)行,也就是說,gulp 會一次性運行所有的 task 并且不做任何等待。
但是如果我們想要它同步執(zhí)行任務(wù)呢?應(yīng)該怎么做?看代碼
- 同步執(zhí)行任務(wù)
const gulp = require('gulp');
// 壓縮css代碼
gulp.task('css', function () {
gulp.src('src/css/*.css')
.pipe(concat('bundle.css'))
.pipe(cleanCss()) // 壓縮css文件
.pipe(gulp.dest('dist/css/'))
})
// 解析less代碼并且壓縮css代碼
gulp.task('less', function () {
gulp.src('src/less/*.less')
.pipe(concat('bundle_less.less'))
.pipe(less())
.pipe(cleanCss())
.pipe(rename({
suffix: '.min'
}))
.pipe(gulp.dest('dist/less'))
})
// 執(zhí)行數(shù)組內(nèi)的任務(wù)
gulp.task('default', ['js', 'css'], 'less')
輸出結(jié)果
[11:44:22] Using gulpfile E:\練習(xí)\Gulp\4-12\gulpfile.js
[11:44:22] Starting 'css'...
[11:44:22] Finished 'css' after 7.24 ms
[11:44:22] Starting 'less'...
[11:44:22] Finished 'less' after 3.01 ms
[11:44:22] Starting 'default'...
[11:44:22] Finished 'default' after 35 μs
可以看到,我們只需要把return去掉即可實現(xiàn)同步進(jìn)行編譯輸出,也就是說,在task中只要不返回任何值即可實現(xiàn)同步執(zhí)行任務(wù)
如果想特定安排任務(wù)的執(zhí)行順序呢?(同步異步都執(zhí)行)
- 按規(guī)定順序執(zhí)行任務(wù)
const gulp = require('gulp');
// 返回一個 callback,因此系統(tǒng)可以知道它什么時候完成
gulp.task('one', function(cb) {
// 做一些事 -- 異步的或者其他的
cb(err); // 如果 err 不是 null 或 undefined,則會停止執(zhí)行,且注意,這樣代表執(zhí)行失敗了
});
// 定義一個所依賴的 task 必須在這個 task 執(zhí)行之前完成
gulp.task('two', ['one'], function() {
// 'one' 完成后
});
gulp.task('default', ['one', 'two']);
解析:運行時,gulp會執(zhí)行task one,當(dāng)執(zhí)行該函數(shù)的回調(diào)時候,如果 err 不是 null 或 undefined,則會停止執(zhí)行,且注意,這樣代表執(zhí)行失敗了,如果沒有發(fā)生錯誤,那么才回去執(zhí)行task two。也就是說,任務(wù)two必須在任務(wù)one的后面執(zhí)行
了解常用插件
-
gulp-concat合并文件,減少網(wǎng)絡(luò)請求。基本使用方法:const gulp = require('gulp'), concat = require('gulp-concat'), pump = require('pump'); gulp.task('testConcat', function (cb) { pump([ gulp.src('src/js/*.js'), concat('all.js'),//合并后的文件名 gulp.dest('dist/js') ], cb); }); -
gulp-uglify壓縮js文件,減少文件體積,去掉沒有引用的代碼?;臼褂梅椒ǎ?gulp.task('jsmin',function(){ gulp.src(['src/js/index.js','src/js/detail.js'])//多個文件以數(shù)組形式傳入 .pipe(uglify({ //mangle: true,//類型:Boolean 默認(rèn):true 是否修改變量名 mangle:{except:['require','exports','module','$']},//排除混淆關(guān)鍵字 compress:true,//類型:Boolean 默認(rèn):true 是否完全壓縮 preserveComments:'all'//保留所有注釋 })) .pipe(gulp.dest('dist/js')) }); -
gulp-rename修改文件名,例如將demo.css修改為demo.min.css,一般配合gulp-minify-css/gulp-uglify壓縮插件一起使用?;臼褂梅椒?修改輸出的js文件名):gulp.task('renamejs',function(){ return pump([ gulp.src('src/js/*.js'), rename({suffix: '.min'}), // 輸出文件名修改為帶.min的文件名 uglify(), gulp.dest('dist/js') ]) }) -
gulp-clean-css使用gulp-clean-css壓縮css文件,減小文件大小,并給引用url添加版本號避免緩存。(之前的有同樣功能的gulp-minify-css已被廢棄)?;臼褂梅椒ǎ?gulp.task('testCssmin', function () { gulp.src('src/css/*.css') .pipe(cssmin({ advanced: false, //類型:Boolean 默認(rèn):true [是否開啟高級優(yōu)化(合并選擇器等)] compatibility: 'ie7', //保留ie7及以下兼容寫法 類型:String 默認(rèn):''or'*' [啟用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式] keepBreaks: true, //類型:Boolean 默認(rèn):false [是否保留換行] keepSpecialComments: '*' //保留所有特殊前綴 當(dāng)你用autoprefixer生成的瀏覽器前綴,如果不加這個參數(shù),有可能將會刪除你的部分前綴 })) .pipe(gulp.dest('dist/css')); }); -
gulp-less使用gulp-less插件將less文件編譯成css,當(dāng)有l(wèi)ess文件發(fā)生改變自動編譯less,并保證less語法錯誤或出現(xiàn)異常時能正常工作并提示錯誤信息?;臼褂梅椒ǎ?gulp.task('testLess', function () { gulp.src('src/less/index.less') .pipe(less()) // 解析less文件轉(zhuǎn)換為css .pipe(gulp.dest('src/css')); }); -
gulp-htmlmin使用gulp-htmlmin壓縮html,可以壓縮頁面javascript、css,去除頁面空格、注釋,刪除多余屬性等操作。基本使用方法:const htmlMin = require('gulp-htmlmin'); gulp.task('testHtmlmin', function () { gulp.src('src/html/*.html') .pipe(htmlMin({ removeComments: true,//清除HTML注釋 collapseWhitespace: true,//壓縮HTML collapseBooleanAttributes: true,//省略布爾屬性的值 <input checked="true"/> ==> <input /> removeEmptyAttributes: true,//刪除所有空格作屬性值 <input id="" /> ==> <input /> removeScriptTypeAttributes: true,//刪除<script>的type="text/javascript" removeStyleLinkTypeAttributes: true,//刪除<style>和<link>的type="text/css" minifyJS: true,//壓縮頁面JS minifyCSS: true//壓縮頁面CSS })) // 解析html文件并且壓縮 .pipe(gulp.dest('dist/html')); }); -
gulp-livereload實現(xiàn)項目自動編譯(半自動,頁面不會刷新)?;臼褂梅椒ǎ?const livereload = require('gulp-livereload'); gulp.task('testLess', function () { gulp.src('src/less/index.less') .pipe(less()) // 解析less文件轉(zhuǎn)換為css .pipe(gulp.dest('src/css')) .pipe(livereload()) }); // 這里要先讓默認(rèn)任務(wù)執(zhí)行一遍后 gulp.task('watch', ['default'], function () { // 開啟監(jiān)聽 livereload.listen(); // 確認(rèn)監(jiān)聽的目標(biāo)文件和對應(yīng)所執(zhí)行的task gulp.watch('src/less/*.less', ['testLess']); gulp.watch('src/html/*.html', ['minHtml']); }) -
gulp-connect實現(xiàn)實時編譯和瀏覽器自動刷新(全自動)?;臼褂梅椒ǎ?const connect = require('gulp-connect'); gulp.task('css', function () { return pump([ gulp.src('src/css/*.css'), concat('bundle.css'), cleanCss(), rename({ suffix: '.min' }), gulp.dest('dist/css/'), connect.reload() // 這一句實現(xiàn)修改后會刷新 ]) }) gulp.task('server', ['default'], function () { connect.server({ root: 'dist/', // 編譯后對應(yīng)映射到哪個文件目錄下 port: 8080, // 端口號 livereload: true // 使用自動編譯 }); gulp.watch('src/css/*.css', ['css']); gulp.watch('src/html/*.html', ['minHtml']); }) -
gulp-autoprefixer實現(xiàn)版本自動添加前綴?;臼褂梅椒ǎ?const autoprefixer = require('gulp-autoprefixer') /*自動加前綴*/ gulp.task('autoprefixer', function () { return gulp.src('css/*.css') .pipe(autoprefixer({ browsers: ["last 2 versions","Firefox >= 20"], /*last 2 versions: 主流瀏覽器的最新兩個版本 ● last 1 Chrome versions: 谷歌瀏覽器的最新版本 ● last 2 Explorer versions: IE的最新兩個版本 ● last 3 Safari versions: 蘋果瀏覽器最新三個版本 ● Firefox >= 20: 火狐瀏覽器的版本大于或等于20 ● iOS 7: IOS7版本 ● Firefox ESR: 最新ESR版本的火狐 ● > 5%: 全球統(tǒng)計有超過5%的使用率 */ cascade: true, //是否美化屬性值 默認(rèn):true 像這樣: //-webkit-trans==>m: rotate(45deg); // trans==>m: rotate(45deg); remove:true //是否去掉不必要的前綴 默認(rèn):true })) .pipe(gulp.dest('css/')); }); -
gulp-load-plugins所有的gulp插件都存在這里面。基本使用方法:// 必須要先調(diào)用一下這個函數(shù)才能使用 const $ = require('gulp-load-plugins')(); // 此時, 這些不在需要引入 const concat = require('gulp-concat'); const uglify = require('gulp-uglify'); const rename = require('gulp-rename'); const cleanCss = require('gulp-clean-css'); ... // 使用下面的寫法代替上面的插件 $.concat $.uglify $.rename $.cleanCss $.htmlmin ... -
gulp-babel編譯ES6、7轉(zhuǎn)換為ES5?;臼褂梅椒ǎ?const babel = require('gulp-babel'); gulp.task('es', function () { return gulp.src('src/js_es6/*.js') .pipe(babel({ // 編譯es6語法 presets: ["@babel/env"], plugins: [] })) .pipe(concat('bundle.js')) .pipe(gulp.dest('dist/')) }) gulp.task('default', gulp.series(['es'])) // 依賴版本 // "@babel/core": "^7.4.3", // "@babel/preset-env": "^7.4.3", // "gulp": "^4.0.0", // "gulp-babel": "^8.0.0",
Gulp4.0升級了什么
-
gulp在gulp.task()中移除了三參數(shù)語法,現(xiàn)在不能使用數(shù)組來指定一個任務(wù)的依賴。gulp 4.0 加入了 gulp.series 和 gulp.parallel 來實現(xiàn)任務(wù)的串行化和并行化。gulp.series 用于串行(順序)執(zhí)行
gulp.task('default', gulp.series(['html', 'css', 'js']))gulp.parallel 用于并行執(zhí)行,如果你想并行執(zhí)行scripts和styles,你可以這么寫:
gulp.task('default', gulp.parallel('scripts', 'styles'));通常gulp.series 和 gulp.parallel我們需要配合來使用。
-
依賴陷阱
讓我們看一下這個Gulp3的例子:
// default任務(wù),需要依賴scripts和styles gulp.task('default', ['scripts', 'styles'], function() {}); // script和styles任務(wù)都依賴clean gulp.task('styles', ['clean'], function() {}); gulp.task('scripts', ['clean'], function() {}); // clean任務(wù)用來清空目錄 gulp.task('clean', function() {});當(dāng)Gulp開始工作,它會創(chuàng)建一個任務(wù)依賴樹
它發(fā)現(xiàn)clean任務(wù)是另外兩個task的依賴,從而確保clean只執(zhí)行一次。
但遺憾的是,我們在新版本中將沒辦法運用這個特性。如果你在遷移到Gulp4的過程中只像下面的例子一樣做了簡單的改變,clean任務(wù)將會被執(zhí)行兩次:
// 任務(wù)直接不再有依賴 gulp.task('styles', function() {...}); gulp.task('scripts', function() {...}); gulp.task('clean', function() {...}); // default任務(wù),需要依賴scripts和styles gulp.task('default', gulp.series('clean', gulp.parallel('scripts', 'styles'))); -
異步任務(wù)支持
如果你執(zhí)行的是同步任務(wù),在Gulp3中不需要寫任何其他代碼,但是在Gulp4中就不能如此輕松了:現(xiàn)在也你必須運行done回調(diào)(這可能是我最早發(fā)現(xiàn)的一個變化)。然后如果你執(zhí)行的是異步任務(wù),你則有三個選擇來確保Gulp能夠檢測到你的任務(wù)真的完成了:
- 回調(diào)
const del = require('del'); // del 模塊用來刪除指定目錄的文件 gulp.task('clean', function(done) { del(['.build/'], done); });- 流
返回一個流告訴gulp任務(wù)你已經(jīng)處理完成gulp.task('somename', function() { return gulp.src('client/**/*.js') .pipe(minify()) .pipe(gulp.dest('build')); }); - Promise
返回一個Promise來告訴gulp任務(wù)已經(jīng)處理完成var promisedDel = require('promised-del'); gulp.task('clean', function() { return promisedDel(['.build/']); });
-
使用函數(shù)定義任務(wù)
具體使用方法:
// 只需要在`series` 和 `parallel` 中間引用函數(shù)名就能組成一個新任務(wù) gulp.task('default', gulp.series(clean, gulp.parallel(scripts, styles))); // 把單個任務(wù)變成一個函數(shù) function styles() {} function scripts() {} function clean() {}此處參考了:
【譯】相對完整的Gulp4升級指南
Gulp 4: gulp.parallel gulp.series -- 全新的任務(wù)執(zhí)行體系