最简单的案例

安装:
npm install —g gulp-cli
npm install —save-dev gulp

注册任务并执行
项目根目录下需要有gulpfile.js作为配置文件,执行gulp命令时后面需要加上任务名,这个任务名是在gulpfile.js配置文件中挂在exports上的方法,例如:

  1. function callbackTask(done) {
  2. setTimeout(() => {
  3. console.log('callbackTask')
  4. done()
  5. }, 1000)
  6. }
  7. exports.callback = callbackTask

在命令行执行gulp callback即可

gulp中只有异步任务,同步任务已经被废弃

各种异步任务类型:

  1. const fs = require('fs');
  2. const through = require('through2');
  3. function callbackTask(done) {
  4. setTimeout(() => {
  5. console.log('callbackTask');
  6. done();//调用done方法就表示任务完成了
  7. }, 1000);
  8. }
  9. function promiseTask() {
  10. return new Promise((resolve, reject) => {
  11. setTimeout(() => {
  12. console.log('promiseTask');
  13. resolve();//调用resolve方法就表示promise成功了
  14. }, 1000);
  15. });
  16. }
  17. async function asyncTask() {
  18. await new Promise(resolve => {
  19. setTimeout(() => {
  20. console.log('asyncTask');
  21. resolve();//调用resolve方法就表示promise成功了
  22. }, 1000);
  23. });
  24. }
  25. function streamTask() {
  26. //流的操作其实也是异步的,这个任务也需要等待流这个异步任务之后才会让任务结束
  27. let rs = fs.createReadStream('input.txt', { autoClose: true });
  28. let ws = fs.createWriteStream('output.txt', { autoClose: true });
  29. return rs.pipe(through((chunk, enc, next) => {
  30. setTimeout(() => {
  31. next(null, chunk.toString() + "$");
  32. }, 1000);
  33. })).pipe(ws, { end: true }).on('end', () => console.log('end'));
  34. }
  35. exports.callback = callbackTask;
  36. exports.promise = promiseTask;
  37. exports.async = asyncTask;
  38. 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