最简单的案例
安装:
npm install --g gulp-cli
npm install --save-dev gulp
注册任务并执行
项目根目录下需要有gulpfile.js作为配置文件,执行gulp命令时后面需要加上任务名,这个任务名是在gulpfile.js配置文件中挂在exports上的方法,例如:
function callbackTask(done) {
setTimeout(() => {
console.log('callbackTask')
done()
}, 1000)
}
exports.callback = callbackTask
在命令行执行gulp callback即可
gulp中只有异步任务,同步任务已经被废弃
各种异步任务类型:
const fs = require('fs');
const through = require('through2');
function callbackTask(done) {
setTimeout(() => {
console.log('callbackTask');
done();//调用done方法就表示任务完成了
}, 1000);
}
function promiseTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('promiseTask');
resolve();//调用resolve方法就表示promise成功了
}, 1000);
});
}
async function asyncTask() {
await new Promise(resolve => {
setTimeout(() => {
console.log('asyncTask');
resolve();//调用resolve方法就表示promise成功了
}, 1000);
});
}
function streamTask() {
//流的操作其实也是异步的,这个任务也需要等待流这个异步任务之后才会让任务结束
let rs = fs.createReadStream('input.txt', { autoClose: true });
let ws = fs.createWriteStream('output.txt', { autoClose: true });
return rs.pipe(through((chunk, enc, next) => {
setTimeout(() => {
next(null, chunk.toString() + "$");
}, 1000);
})).pipe(ws, { end: true }).on('end', () => console.log('end'));
}
exports.callback = callbackTask;
exports.promise = promiseTask;
exports.async = asyncTask;
exports.stream = streamTask;
命令行分别执行gulp callback/gulp promise/gulp async/gulp stream即可触发对应任务
gulp还可以注册组合任务,来完成异步串行、异步并行的操作
const fs = require('fs');
const through = require('through2');
const { series, parallel } = require('gulp');
function callbackTask(done) {
...
}
function promiseTask() {
...
}
async function asyncTask() {
...
}
function streamTask() {
...
}
// parallel类似Promise.all,实现异步并行
const parallelTask = parallel(callbackTask, promiseTask, asyncTask, streamTask);
// parallel类似Promise.all,实现异步串行
const seriesTask = series(callbackTask, promiseTask, asyncTask, streamTask);
exports.callback = callbackTask;
exports.promise = promiseTask;
exports.async = asyncTask;
exports.stream = streamTask;
exports.parallel = parallelTask;//Promise.all
exports.series = seriesTask;
文件拷贝任务:
const { src, dest } = require('gulp');
function copyTask() {
console.log('执行拷贝文件');
return src('src/scripts/**/*.js').pipe(dest('dist'))
}
export.copy = copyTask
注:
dest指定的是输出的目录名,不包括文件路径
文件路径或者说文件名是glob里通配符开始的路径部分,此处就是src/scripts//*.js中/*.js对应的部分
本案例中src/scripts下有main.js这个文件,所以在进程执行的目录下会生成dist,将打包后的文件放到这个目录下
如果想要自定义打包后的目录,可以指定base属性,例如:
src('src/scripts/**/*.js', { base: 'src' }).pipe(dest('dist'))
就可以将src作为基准目录,src后面的scripts也会成为打包后的目录,打包后的目录中将会包含scripts
以此来推测,gulp打包后的目标文件和源文件的目录结构是非常像的
注:
出于某些包的实现方式的原因,如果需要使用esm模块规范,则需要通过import动态引入来实现,例如压缩图片的任务就是这样:
const images = async () => {
const imagemin = await import('gulp-imagemin');
return src("src/assets/images/**/*.@(jpg|png|gif|svg)", { base: 'src' })
.pipe(imagemin.default())
.pipe(dest('dist'))
}
exports.images = images;
各种任务:
const { src, dest, parallel, watch, series } = require('gulp');
const plugins = require('gulp-load-plugins')();
const browserSync = require('browser-sync');
const browserServer = browserSync.create();
//清除输出目录
const clean = () => {
return src(["dist/**", "temp/**"], { read: false })
.pipe(plugins.clean())
}
//编译样式
const styles = () => {
return src("src/styles/**/*.less", { base: 'src' })
.pipe(plugins.less())
.pipe(dest('temp'))
}
//编译JS脚本
const scripts = () => {
return src("src/scripts/**/*.js", { base: 'src' })
.pipe(plugins.babel({
presets: ["@babel/preset-env"]
}))
.pipe(dest('temp'))
}
//编译html模板
const html = () => {
return src("src/**/*.html", { base: 'src' })
.pipe(plugins.ejs({ "title": 'gulp实战' }, { cache: false }))
.pipe(dest('temp'))
}
//压缩图片
const images = async () => {
const imagemin = await import('gulp-imagemin');
return src("src/assets/images/**/*.@(jpg|png|gif|svg)", { base: 'src' })
//.pipe(imagemin.default())
.pipe(dest('dist'))
}
//拷贝不需要任务编译 处理的静态文件,到输出目录
const static = () => {
return src("static/**", { base: 'static' })
.pipe(dest('dist'))
}
const serve = () => {
watch('src/styles/**/*.less', styles).on('change', browserSync.reload);;
watch('src/scripts/**/*.js', scripts).on('change', browserSync.reload);;
watch('src/**/*.html', html).on('change', browserSync.reload);;
watch([
"src/assets/images/**/*.@(jpg|png|gif|svg)",
"static/**"
], browserServer.reload);
//serve和webpack-dev-server里的打包不一样,serve不会在内存和硬盘上生成任何文件,
//webpack-dev-server也只读内存中的文件,webpack打包生成到内存里,
return browserServer.init({
notify: false,
server: {
baseDir: ['temp', "src", "static"],//静态文件根目录
files: ['dist/**'],//监听 文件变化,文件变化后重新刷新浏览器
routes: {
'/node_modules': 'node_modules'
}
}
});
}
const concat = () => {
//src index.html
//经过useref处理之后变成 里面有三个文件了index.html build.css build.js
return src('temp/**/*.html', { base: 'temp' })
.pipe(plugins.useref({ searchPath: ['temp', '.'] }))
.pipe(plugins.if('*.js', plugins.uglify()))
.pipe(plugins.if('*.css', plugins.cleanCss()))
.pipe(plugins.if('*.html', plugins.htmlmin({
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})))
.pipe(dest('dist'))
}
//把需要编译 的任务组合在一起,成为一个并发执行的组合任务
const compile = parallel(styles, scripts, html);
const build = series(clean, parallel(series(compile, concat), images, static));
const dev = series(clean, compile, serve);
//生成环境构建
exports.build = build;
//开发环境预览
exports.dev = dev;
///assets/images/circle.svg
// dist/assets/images/circle.svg
// src/assets/images/circle.svg
///rect.svg
//dist/rect.svg
// src/rect.svg
// static/rect.svg