阅读原文javascript
Gulp官网css
gulp4.0分离了cli和核心部分,因此须要分别安装这两个包,另外对环境要求以下:html
node >= 8.11.1
npm >= 5.6.0
npx >= 9.7.1
复制代码
npm i -g gulp-cli
复制代码
npm i -D gulp
复制代码
$ gulp -v
# 输出
CLI version: 2.2.0
Local version: 4.0.2
复制代码
在项目根目录建立gulpfile.js
文件(若是使用ts或者babel,也可用gulpfile.ts
、gulpfile.babel.js
分别代替),此文件即gulp会默认读取的配置文件,咱们能够在里面配置须要的task。 若是task较多或者较复杂,能够建立gulpfile.js
目录,在目录中拆分task为多个文件,只要保证该目录下有个index.js
做为入口便可。java
task分为两种:node
const { series, parallel } = require('gulp');
// Private tasks
function clean(cb) {
// body omitted
cb();
}
// Private tasks
function build(cb) {
// body omitted
cb();
}
exports.build = build; // Public tasks, 执行gulp build
exports.default = series(clean, parallel(css, javascript)); // Public tasks, 执行gulp
复制代码
注意: 在task中,操做完成时,咱们必需要经过cb()或者return的方式来告知gulp此任务已完成。webpack
// cb
function clean(cb) {
del(['dist]); cb(); }); // return function minifyjs() { return src('src/**/*.js') .pipe(minify()) .pipe(dest('dist')); }); function promiseTask() { return new Promise(function(resolve, reject) { // body omitted resolve(); }); }); 复制代码
gulp <export task name>
gulp // 导出为default的task能够直接运行gulp
复制代码
// task1执行完再执行task2
exports.taskName = series(task1, task2)
复制代码
// task1和task2同时执行
exports.taskName = parallel(task1, task2)
复制代码
exports.taskName = series(clean, parallel(css, javascript))
复制代码
gulp借鉴了Unix的管道(pipe)思想,处理文件采用流的方式,前一步的输出做为后一步的输入,中途不会在磁盘写入文件,仅在dest时输出文件,因此很是快速高效。web
gulp提供了src及dest方法分别来进行文件读入、输出操做,同时提供了pipe管道方法来链式执行其余操做。正则表达式
const { src, dest } = require('gulp');
// 将src目录下的全部js输出到output目录
exports.default = function() {
return src('src/*.js')
.pipe(dest('output/'));
}
复制代码
若是咱们想在中途添加文件能够采用以下方式:npm
const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');
exports.default = function() {
return src('src/*.js')
.pipe(uglify())
.pipe(src('vendor/*.js')) // 添加文件
.pipe(dest('output/'));
}
复制代码
固然咱们也能够进行屡次输出:gulp
const { src, dest } = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
exports.default = function() {
return src('src/*.js')
.pipe(babel())
.pipe(dest('temp/'))
.pipe(uglify())
.pipe(dest('output/'));
}
复制代码
每每咱们在使用src方法的时候须要输入多个或者一类文件,而不只仅是某个具体的文件,这时咱们就可使用gulp提供的匹配规则来处理。
"src/file.js"
:单个文件["src/file1,src/file2.js"]
:多个文件*
: 全部文件src('src/*.js') // src自身目录全部的js文件,不含后代文件夹中
src('src/a*c.js')
复制代码
**
:0或者多个文件夹src('src/**/*.js') // src目录全部的js文件,含后代文件夹中的
复制代码
{}
:多个属性src('src/*.{jpg,png,gif}') // src自身目录下的全部jpg、png和gif文件
复制代码
!
:排除src(['**/*.js', '!node_modules/**']) // 全部的js文件,可是node_modules下的除外
复制代码
注意:src 接收的文件匹配字符串会顺序解释,因此你能够写成这样 gulp.src(['.js', '!b.js', 'bad.js'])
(排除全部以 b 开头的 JS 文件可是除了 bad.js
)
匹配符 说明
* 匹配文件路径中的0个或多个字符,但不会匹配路径分割符,
除非分隔符出如今末尾
** 匹配路径的0个会多个目录 及子目录 须要单独出现,
即他左右不能有其余的东西了若是出如今末尾,也能匹配文件
? 匹配文件路径中的一个字符(不能匹配路径分割符/)
[...] 匹配方括号中 出现字符的任意一个,当方括号中第一个字符为^或!时,
则表示不匹配方括号中出现字符中的任意一个,
相似于js中正则表达式中的用法
!(pattern|pattern|pattern) 匹配任何与括号中给定的任意模式都不匹配
?(pattern|pattern|pattern) 匹配括号中给定的任意模式0次或1次
+(pattern|pattern|pattern) 匹配括号中的至少一次
*(pattern|pattern|pattern) 匹配括号中给定的任意模式0次或屡次
@(pattern|pattern|pattern) 匹配括号中 给定的任意模式一次
复制代码
gulp推荐每一个插件应该只专一的作一小部分工做,而后经过pipe将它们链接起来,就能够完成咱们须要作的事情。
const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename');
exports.default = function() {
return src('src/*.js')
// The gulp-uglify plugin won't update the filename .pipe(uglify()) // So use gulp-rename to change the extension .pipe(rename({ extname: '.min.js' })) .pipe(dest('output/')); } 复制代码
固然,除了插件,咱们也可使用其余库:
const del = require('delete');
exports.default = function(cb) {
// Use the `delete` module directly, instead of using gulp-rimraf
del(['output/*.js'], cb);
}
复制代码
最后也能够借助through2插件使用内联方式自行处理,也能够利用次through2进行gulp插件开发:
const { src, dest } = require('gulp');
const uglify = require('uglify-js');
const through2 = require('through2');
exports.default = function() {
return src('src/*.js')
// Instead of using gulp-uglify, you can create an inline plugin
.pipe(through2.obj(function(file, _, cb) {
if (file.isBuffer()) {
const code = uglify.minify(file.contents.toString())
file.contents = Buffer.from(code)
}
cb(null, file);
}))
.pipe(dest('output/'));
}
复制代码
咱们可使用watch方法来监听文件的改动,以便在改动时执行相应的处理任务。
const { watch, series } = require('gulp');
function clean(cb) {
// body omitted
cb();
}
function javascript(cb) {
// body omitted
cb();
}
function css(cb) {
// body omitted
cb();
}
exports.default = function() {
watch('src/*.css', css);
watch('src/*.js', series(clean, javascript));
};
复制代码
src(globs, [options])
:输入globs[string|array]
: 要处理文件的路径匹配规则options
:配置项,点击查看详情const { src, dest } = require('gulp');
function copy() {
return src('input/*.js', { sourcemaps: true })
.pipe(dest('output/'));
}
复制代码
dest(directory, [options])
:输出directory[string|function]
: 输出的路径options
:配置项,点击查看详情const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');
src('input/**/*.js', { sourcemaps: true })
.pipe(uglify())
.pipe(dest('output/', { sourcemaps: '.' }));
复制代码
注意: dest的路径默认是基于当前路径,并非输入文件的路径,若是须要输出到输入文件的相对路径,可使用gulp-rename
插件来实现。如我要将全部目录下的scss目录中的scss文件输出到scss同目录的css文件中:
src('./SCOs/**/scss/*.scss')
.pipe(sass())
.pipe(rename(path=> path.dirname += '../../css'))
.pipe(dest('./SCOs'));
复制代码
series(...tasks)
:顺序执行多个任务tasks[function|string]
:任务名或者functionconst { series } = require('gulp');
function javascript(cb) {
// body omitted
cb();
}
function css(cb) {
// body omitted
cb();
}
exports.build = series(javascript, css);
复制代码
parallel(...tasks)
:多个任务同时执行tasks[function|string]
:任务名或者functionconst { parallel } = require('gulp');
function javascript(cb) {
// body omitted
cb();
}
function css(cb) {
// body omitted
cb();
}
exports.build = parallel(javascript, css);
复制代码
watch(globs, [options], [task])
:文件监听globs[string|array]
: 要监听的文件options
:配置项,点击查看详情task[function|string]
:要执行的任务或操做const { watch } = require('gulp');
watch(['input/*.js', '!input/something.js'], function(cb) {
// body omitted
cb();
});
复制代码
监听方法会返回一共实例,该实例提供了以下几个方法:
watcher.on(eventName, eventHandler)
eventName[string]
:事件名称,能够是add
, addDir
, change
, unlink
, unlinkDir
, ready
, error
, or all
eventHandler[function]
:事件处理函数,该函数接收path和stats两个参数。const { watch } = require('gulp');
const watcher = watch(['input/*.js']);
watcher.on('change', function(path, stats) {
console.log(`File ${path} was changed`);
});
watcher.on('add', function(path, stats) {
console.log(`File ${path} was added`);
});
watcher.on('unlink', function(path, stats) {
console.log(`File ${path} was removed`);
});
watcher.close();
复制代码
watcher.close()
:关闭文件监听器watcher.add(globs)
:添加文件到监听器globs[string|array]
: 要添加的文件watcher.unwatch(globs)
:移除监听器中的文件globs[string|array]
: 要移除的文件task([taskName], taskFunction)
:定义任务(4.0推荐使用function替代此方法)taskName[string]
:任务名称taskFunction[function]
:处理函数const { task } = require('gulp');
task('build', function(cb) {
// body omitted
cb();
});
const build = task('build');
复制代码
lastRun(task, [precision])
:获取任务最后运行完成的时间戳task[function|string]
:指定获取的任务precision[number]
:精度,默认1000 可以使用此方法进行增量编译。const { src, dest, lastRun, watch } = require('gulp');
const imagemin = require('gulp-imagemin');
function images() {
return src('src/images/**/*.jpg', { since: lastRun(images) })
.pipe(imagemin())
.pipe(dest('build/img/'));
}
exports.default = function() {
watch('src/images/**/*.jpg', images);
};
复制代码
tree([options])
:获取任务依赖关系options[object]
:deep默认为false,只会返回顶级任务,若是为true,则会返回整个任务树。gulp.tree({ deep: true })
复制代码
Vinyl
:一个文件描述器,本身开发插件可能会用到具体的用法见gulp源码解析(二)—— vinyl-fs
我经常使用的api就这些,其余的api能够自行查看官方文档。
若是要查找gulp插件,通常有两个地方:
总结:
gulp自己其实很是简单,提供的api不多,可是简洁够用。在了解这些api后,你可能以为最复杂的仍是了解各插件的用法。
其实,构建工具(gulp、webpack之类)自己都是相对较简单的,这才是它们该有的样子,自己就很复杂了,我才懒得用。可是在使用过程当中,我以为有两个难点:
最后,本人才疏学浅,有不妥之处,欢迎指正。