Gulp
是基于流的自动化构建工具,它不仅能对网站资源进行优化,而且在开发过程中能避免很多重复的工作,比如对相关文件的操作,还有自动监视一些文件的变化等功能。
基本的常用API(gulp v3.X)
-
gulp.src(globs[, options])
输出符合所提供的匹配模式或者匹配模式的数组的文件。 将返回一个stream文件流它可以被 piped 到别的插件中。
glob 相当于文件的路径,或者文件路径数组。 gulp.dest(path[, options])
// 把上一步处理的数据输出到指定的目录path中,如果某文件夹不存在,将会自动创建它。-
gulp.task(name[, deps], fn)
例子:
gulp.task('mytask', ['array', 'of', 'task', 'names'], function() { // 做一些事 });
异步、同步、规定执行顺序执行任务
-
异步执行任务
const gulp = require('gulp'); // 压缩js代码 gulp.task('js', function () { return gulp.src('src/js/*.js') // 匹配参数内的文件,并且将文件读到gulp内存中 .pipe(concat('bundle.js')) // 合并文件代码 .pipe(gulp.dest('dist/js/')) // 输出文件到指定目录 .pipe(uglify()) // 压缩当前的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/')) })
// 执行数组内的任务 gulp.task('default', ['js', 'css'])
当运行命令 gulp
后,我们发现输出的是
[11:31:43] Using gulpfile E:\练习\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
可以看到此时的任务是异步执行的,应用官方的一句话就是
默认的,task 将以最大的并发数执行,也就是说,gulp 会一次性运行所有的 task 并且不做任何等待。
但是如果我们想要它同步执行任务呢?应该怎么做?看代码
- 同步执行任务
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'))
})
// 执行数组内的任务
gulp.task('default', ['js', 'css'], 'less')
输出结果
[11:44:22] Using gulpfile E:\练习\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
去掉即可实现同步进行编译输出,也就是说,在task中只要不返回任何值即可实现同步执行任务
如果想特定安排任务的执行顺序呢?(同步异步都执行)
- 按规定顺序执行任务
const gulp = require('gulp');
// 返回一个 callback,因此系统可以知道它什么时候完成
gulp.task('one', function(cb) {
// 做一些事 -- 异步的或者其他的
cb(err); // 如果 err 不是 null 或 undefined,则会停止执行,且注意,这样代表执行失败了
});
// 定义一个所依赖的 task 必须在这个 task 执行之前完成
gulp.task('two', ['one'], function() {
// 'one' 完成后
});
gulp.task('default', ['one', 'two']);
解析:运行时,gulp会执行task one
,当执行该函数的回调时候,如果 err 不是 null 或 undefined,则会停止执行,且注意,这样代表执行失败了,如果没有发生错误,那么才回去执行task two
。也就是说,任务two
必须在任务one
的后面执行
了解常用插件
-
gulp-concat
合并文件,减少网络请求。基本使用方法: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'])//多个文件以数组形式传入 .pipe(uglify({ //mangle: true,//类型:Boolean 默认:true 是否修改变量名 mangle:{except:['require','exports','module','$']},//排除混淆关键字 compress:true,//类型:Boolean 默认: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 默认:true [是否开启高级优化(合并选择器等)] compatibility: 'ie7', //保留ie7及以下兼容写法 类型:String 默认:''or'*' [启用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式] keepBreaks: true, //类型:Boolean 默认:false [是否保留换行] keepSpecialComments: '*' //保留所有特殊前缀 当你用autoprefixer生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀 })) .pipe(gulp.dest('dist/css')); });
-
gulp-less
使用gulp-less插件将less文件编译成css,当有less文件发生改变自动编译less,并保证less语法错误或出现异常时能正常工作并提示错误信息。基本使用方法:gulp.task('testLess', function () { gulp.src('src/less/index.less') .pipe(less()) // 解析less文件转换为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
实现项目自动编译(半自动,页面不会刷新)。基本使用方法:const livereload = require('gulp-livereload'); gulp.task('testLess', function () { gulp.src('src/less/index.less') .pipe(less()) // 解析less文件转换为css .pipe(gulp.dest('src/css')) .pipe(livereload()) }); // 这里要先让默认任务执行一遍后 gulp.task('watch', ['default'], function () { // 开启监听 livereload.listen(); // 确认监听的目标文件和对应所执行的task gulp.watch('src/less/*.less', ['testLess']); gulp.watch('src/html/*.html', ['minHtml']); })
-
gulp-connect
实现实时编译和浏览器自动刷新(全自动)。基本使用方法: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() // 这一句实现修改后会刷新 ]) }) gulp.task('server', ['default'], function () { connect.server({ root: 'dist/', // 编译后对应映射到哪个文件目录下 port: 8080, // 端口号 livereload: true // 使用自动编译 }); gulp.watch('src/css/*.css', ['css']); gulp.watch('src/html/*.html', ['minHtml']); })
-
gulp-autoprefixer
实现版本自动添加前缀。基本使用方法: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%: 全球统计有超过5%的使用率 */ cascade: true, //是否美化属性值 默认:true 像这样: //-webkit-trans==>m: rotate(45deg); // trans==>m: rotate(45deg); remove:true //是否去掉不必要的前缀 默认:true })) .pipe(gulp.dest('css/')); });
-
gulp-load-plugins
所有的gulp插件都存在这里面。基本使用方法:// 必须要先调用一下这个函数才能使用 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转换为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()
中移除了三参数语法,现在不能使用数组来指定一个任务的依赖。gulp 4.0 加入了 gulp.series 和 gulp.parallel 来实现任务的串行化和并行化。gulp.series 用于串行(顺序)执行
gulp.task('default', gulp.series(['html', 'css', 'js']))
gulp.parallel 用于并行执行,如果你想并行执行scripts和styles,你可以这么写:
gulp.task('default', gulp.parallel('scripts', 'styles'));
通常gulp.series 和 gulp.parallel我们需要配合来使用。
-
依赖陷阱
让我们看一下这个Gulp3的例子:
// default任务,需要依赖scripts和styles gulp.task('default', ['scripts', 'styles'], function() {}); // script和styles任务都依赖clean gulp.task('styles', ['clean'], function() {}); gulp.task('scripts', ['clean'], function() {}); // clean任务用来清空目录 gulp.task('clean', function() {});
当Gulp开始工作,它会创建一个任务依赖树
它发现clean任务是另外两个task的依赖,从而确保clean只执行一次。
但遗憾的是,我们在新版本中将没办法运用这个特性。如果你在迁移到Gulp4的过程中只像下面的例子一样做了简单的改变,clean任务将会被执行两次:
// 任务直接不再有依赖 gulp.task('styles', function() {...}); gulp.task('scripts', function() {...}); gulp.task('clean', function() {...}); // default任务,需要依赖scripts和styles gulp.task('default', gulp.series('clean', gulp.parallel('scripts', 'styles')));
-
异步任务支持
如果你执行的是同步任务,在Gulp3中不需要写任何其他代码,但是在Gulp4中就不能如此轻松了:现在也你必须运行done回调(这可能是我最早发现的一个变化)。然后如果你执行的是异步任务,你则有三个选择来确保Gulp能够检测到你的任务真的完成了:
- 回调
const del = require('del'); // del 模块用来删除指定目录的文件 gulp.task('clean', function(done) { del(['.build/'], done); });
- 流
返回一个流告诉gulp任务你已经处理完成gulp.task('somename', function() { return gulp.src('client/**/*.js') .pipe(minify()) .pipe(gulp.dest('build')); });
- Promise
返回一个Promise来告诉gulp任务已经处理完成var promisedDel = require('promised-del'); gulp.task('clean', function() { return promisedDel(['.build/']); });
-
使用函数定义任务
具体使用方法:
// 只需要在`series` 和 `parallel` 中间引用函数名就能组成一个新任务 gulp.task('default', gulp.series(clean, gulp.parallel(scripts, styles))); // 把单个任务变成一个函数 function styles() {} function scripts() {} function clean() {}
此处参考了:
【译】相对完整的Gulp4升级指南
Gulp 4: gulp.parallel gulp.series -- 全新的任务执行体系