Gulp的基本使用
通过导出函数成员的方式定义任务, 默认执行default 任务

yarn add gulp –dev
//gulp的入口文件
exports.foo = done => { 
    console.log('foo task working~')
    done() //标识任务完成
}

exports.default = done => { 
    console.log("default~~~~~");
    done()
};

// gulp4.0之前的写法
// const gulp=reguire('gulp');
// gulp.task('bar',done=>{ 
// console.log('bar working~')
// done()
// })

Gulp创建组合任务

const {  series, parallel } = require('gulp');
const task1 = done => { 
    setTimeout(() => { 
        console.log('task1 working~');
        done()
    }, 1000)
}

const task2 = done => { 
    setTimeout(() => { 
        console.log('task2 working~');
        done()
    }, 1000)
}

const task3 = done => { 
    setTimeout(() => { 
        console.log('task3 working~');
        done()
    }, 1000)
}
exports.foo = series(task1, task2, task3);

foo任务会依次执行task1,task2,task3.
Series是串行的任务
Parallel是并行的任务

Gulp异步任务的三种方式
返回promise
返回流的方式
当从任务(task)中返回 stream、promise、event emitter、child process 或 observable 时,成功或错误值将通知 gulp 是否继续执行或结束。如果任务(task)出错,gulp 将立即结束执行并显示该错误。
当使用 series() 组合多个任务(task)时,任何一个任务(task)的错误将导致整个任务组合结束,并且不会进一步执行其他任务。当使用 parallel() 组合多个任务(task)时,一个任务的错误将结束整个任务组合的结束,但是其他并行的任务(task)可能会执行完,也可能没有执行完。

const {  series, parallel } = require("gulp");
const fs = require('fs')

exports.task_error = (done) => { 
    console.log("task1...");
    // 任务出错 后续的任务不会执行
    // 如果任务出错,就将错误放在回调函数 done 中
  done(new Error('任务出错...'));
};

const time = (time) => { 
    return new Promise(resolve =>{ 
        setTimeout(resolve, time)
    })
    
}
// 异步任务
exports.promise  = () => { 
    // 执行 一个promise 的 resolve 状态也可以结束任务
  return time(1000)
};

// node 8+ 可以使用 async/await async 会隐式返回 promise 所以可以不用写return
exports.promise_async  = async () => { 
    await time(4000)
    console.log('promise_async 任务完成...');
};


exports.promise_error  = () => { 
    console.log('promise_error.........');
    // 返回 一个promise 的 reject 代表任务出错
    return Promise.reject(new Error('promise_error...'))
};


exports.stream  = () => { 
    const readSteam = fs.createReadStream('./package.json')
    const writeSteam = fs.createWriteStream('./tem.txt')
    readSteam.pipe(writeSteam)
    // 一定要返回 流 不然会报错(任务未完成): The following tasks did not complete:
    return readSteam
};

// 流的异步原理: 它自己监听的了流的 end 事件
exports.streamFunc  = (done) => { 
    const readSteam = fs.createReadStream('./package.json')
    const writeSteam = fs.createWriteStream('./tem.txt')
    readSteam.pipe(writeSteam)

    readSteam.on('end', ()=>{ 
        done()
    })
    return readSteam
};

Gulp 构建过程核心工作原理
读取出来, 转换, 写入其他位置

const fs = require("fs");
const {  Transform } = require("stream");
// 模拟 gulp 的原理: 读取流 => 转换流 => 写入流
exports.default = () => { 
  const read = fs.createReadStream("normalize.css");

  // 转换流
  const transform = new Transform({ 
    transform(chunk, encoding, callback) { 
      const input = chunk.toString();
      // 所有换行去除, 所有注释去除
            const output = input.replace(/\s+/g, "").replace(/\/\*.+?\*\//g, "");
            callback(null, output)
    },
  });
  const write = fs.createWriteStream("normalize.min.css");
  read.pipe(transform).pipe(write);
  return read;
};

文件操作API + 插件的使用

yarn add gulp-clean-css --dev
yarn add gulp-rename --dev 
const {  src, dest } = require("gulp");
const cleanCss = require("gulp-clean-css");
const rename = require("gulp-rename");
// 模拟 gulp 的原理: 读取流 => 转换流 => 写入流
exports.default = () => { 
  return (
    src("src/*.css")
      // 压缩 css 
      .pipe(cleanCss())
      // 后缀重命名 
      .pipe(rename({  extname: ".min.css" }))
      .pipe(dest("dist"))
  );
};

Gulp 案例
ps: 如果你yarn 就是下载不了包的话 ,可以换用npm \ cnpm

yarn add gulp --dev
// 处理 sass
yarn add gulp-sass --dev 
// 处理 es6+
yarn add gulp-babel @babel/core @babel/preset-env --dev 
// 模版引擎
yarn add gulp-swig --dev
// 图片处理
yarn add gulp-imagemin --dev
// 自动加载gulp插件 解决文件顶部插件引入很多,导致代码比较繁杂的问题
 yarn add gulp-load-plugins --dev 
 // 清除文件 
 yarn add del --dev 
 // 开发服务器 支持HMR
 yarn add browser-sync --dev 
 // 处理文件引用关系
 yarn add gulp-useref --dev 
 // 压缩文件
 yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev 
 // 判断 流的类型
 yarn add gulp-if --dev 
 
 
 项目启动的其他依赖
 yarn add bootstrap jquery popper.js 

grupfile.js

样式编译
scss 转 css
转 css 时 保留文件路径
输出到 dist 目录

const {  src, dest } = require("gulp");
const sass = require("gulp-sass");

// scss 转 css
const style = () => { 
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", {  base: "src" })
      // scss 处理 并保留花括号换行
      .pipe(sass({  outputStyle: "expanded" }))
      .pipe(dest("dist"))
  );
};

module.exports = { 
  style,
};

测试:
yarn gulp style

脚本编译

const {  src, dest } = require("gulp");
const sass = require("gulp-sass");
const babel = require('gulp-babel')

// scss 转 css
const style = () => { 
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", {  base: "src" })
      // scss 处理 并保留花括号换行
      .pipe(sass({  outputStyle: "expanded" }))
      .pipe(dest("dist"))
  );
};

const script = () => { 
  // 指定从 src 下保留路径
  return (
    src("src/assets/scripts/*.js", {  base: "src" })
      // ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
      .pipe(babel({  presets: ['@babel/preset-env'] }))
      .pipe(dest("dist"))
  );
};

module.exports = { 
    style,
    script
};

测试:
yarn gulp script

页面模板编译

const {  src, dest, parallel } = require("gulp");
const sass = require("gulp-sass");
const babel = require("gulp-babel");
const swig = require("gulp-swig");

const data = { 
  menus: [
    { 
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    { 
      name: "Features",
      link: "features.html",
    },
    { 
      name: "About",
      link: "about.html",
    },
    { 
      name: "Contact",
      link: "#",
      children: [
        { 
          name: "Twitter",
          link: "https://twitter.com/w_zce",
        },
        { 
          name: "About",
          link: "https://weibo.com/zceme",
        },
        { 
          name: "divider",
        },
        { 
          name: "About",
          link: "https://github.com/zce",
        },
      ],
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};

// scss 转 css
const style = () => { 
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", {  base: "src" })
      // scss 处理 并保留花括号换行
      .pipe(sass({  outputStyle: "expanded" }))
      .pipe(dest("dist"))
  );
};

const script = () => { 
  // 指定从 src 下保留路径
  return (
    src("src/assets/scripts/*.js", {  base: "src" })
      // ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
      .pipe(babel({  presets: ["@babel/preset-env"] }))
      .pipe(dest("dist"))
  );
};

const page = () => { 
  // src/**/*.html 匹配任意子目录
  return src("src/*.html", {  base: "src" })
    .pipe(swig({  data }))
    .pipe(dest("dist"));
};

// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page)

module.exports = { 
    compile
};

测试:
yarn gulp compile

图片和字体文件的转换

const {  src, dest, parallel } = require("gulp");

const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
// const sass = require("gulp-sass");
// const babel = require("gulp-babel");
// const swig = require("gulp-swig");
// const imagemin = require("gulp-imagemin");


const data = { 
  menus: [
    { 
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    { 
      name: "Features",
      link: "features.html",
    },
    { 
      name: "About",
      link: "about.html",
    },
    { 
      name: "Contact",
      link: "#",
      children: [
        { 
          name: "Twitter",
          link: "https://twitter.com/w_zce",
        },
        { 
          name: "About",
          link: "https://weibo.com/zceme",
        },
        { 
          name: "divider",
        },
        { 
          name: "About",
          link: "https://github.com/zce",
        },
      ],
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};

// scss 转 css
const style = () => { 
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", {  base: "src" })
      // scss 处理 并保留花括号换行
      .pipe(plugins.sass({  outputStyle: "expanded" }))
      .pipe(dest("dist"))
  );
};

// 编译脚本文件
const script = () => { 
  // 指定从 src 下保留路径
  return (
    src("src/assets/scripts/*.js", {  base: "src" })
      // ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
      .pipe(plugins.babel({  presets: ["@babel/preset-env"] }))
      .pipe(dest("dist"))
  );
};

// 编译模板文件
const page = () => { 
  // src/**/*.html 匹配任意子目录
  return src("src/*.html", {  base: "src" })
    .pipe(plugins.swig({  data }))
    .pipe(dest("dist"));
};

// 转换图片文件
const image = () => { 
  // 匹配文件下的所有文件
  return src("src/assets/images/**").pipe(plugins.imagemin()).pipe(dest("dist"));
};

// 转换字体文件, 一般的字体文件不需要压缩等处理, 但是有些svg格式的文件,还是可以稍微处理一下
const font = () => { 
  // 匹配文件下的所有文件
  return src("src/assets/fonts/**").pipe(plugins.imagemin()).pipe(dest("dist"));
};

// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page, image, font);

module.exports = { 
  compile,
};

其他文件清除

const {  src, dest, parallel, series, watch } = require("gulp");
const del = require("del");
const loadPlugins = require("gulp-load-plugins");
const bs = require("browser-sync");
const plugins = loadPlugins();
// const sass = require("gulp-sass");
// const babel = require("gulp-babel");
// const swig = require("gulp-swig");
// const imagemin = require("gulp-imagemin");
const data = { 
menus: [
{ 
name: "Home",
icon: "aperture",
link: "index.html",
},
{ 
name: "Features",
link: "features.html",
},
{ 
name: "About",
link: "about.html",
},
{ 
name: "Contact",
link: "#",
children: [
{ 
name: "Twitter",
link: "https://twitter.com/w_zce",
},
{ 
name: "About",
link: "https://weibo.com/zceme",
},
{ 
name: "divider",
},
{ 
name: "About",
link: "https://github.com/zce",
},
],
},
],
pkg: require("./package.json"),
date: new Date(),
};
// 清除文件
const clean = () => { 
// del 返回的是个 promise
return del(["dist"]);
};
// scss 转 css
const style = () => { 
// 指定从 src 下保留路径
return (
src("src/assets/styles/*.scss", {  base: "src" })
// scss 处理 并保留花括号换行
.pipe(plugins.sass({  outputStyle: "expanded" }))
.pipe(dest("dist"))
.pipe(bs.reload({  stream: true }))
);
};
// 编译脚本文件
const script = () => { 
// 指定从 src 下保留路径
return (
src("src/assets/scripts/*.js", {  base: "src" })
// ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
.pipe(plugins.babel({  presets: ["@babel/preset-env"] }))
.pipe(dest("dist"))
.pipe(bs.reload({  stream: true }))
);
};
// 编译模板文件
const page = () => { 
// src/**/*.html 匹配任意子目录
return src("src/*.html", {  base: "src" })
.pipe(plugins.swig({  data, defaults: {  cache: false } })) // 防止模板缓存导致页面不能及时更新
.pipe(dest("dist"))
.pipe(bs.reload({  stream: true }));
};
// 转换图片文件
const image = () => { 
// 匹配文件下的所有文件
return src("src/assets/images/**", {  base: "src" })
.pipe(plugins.imagemin())
.pipe(dest("dist"));
};
// 转换字体文件, 一般的字体文件不需要压缩等处理, 但是有些svg格式的文件,还是可以稍微处理一下
const font = () => { 
// 匹配文件下的所有文件
return src("src/assets/fonts/**", {  base: "src" })
.pipe(plugins.imagemin())
.pipe(dest("dist"));
};
const serve = () => { 
watch("src/assets/styles/*.scss", style);
watch("src/assets/scripts/*.js", script);
watch("src/*.html", page);
// 这几个静态资源, 开发过程中没必要构建
// watch('src/assets/images/**', image)
// watch('src/assets/fonts/**', font)
// watch('public/**', public)
watch(
["src/assets/images/**", "src/assets/fonts/**", "public/**"],
bs.reload
);
bs.init({ 
notify: false, // browser-sync 连接提示
port: 2080,
open: true, // 自动打开浏览器窗口
// files: "dist/**", // 监听dist文件变化
server: { 
baseDir: ["dist", "src", "public"],
routes: { 
"/node_modules": "node_modules",
},
},
});
};
//public 原样输出到 dist
const public = () => { 
return src("public/**", {  base: "public" }).pipe(dest("dist"));
};
// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page);
// 先清空文件夹, 再编译+复制public文件夹  正式打开再处理 静态资源文件
const build = series(clean, parallel(compile, public, image, font));
const develop = series(compile, serve);
module.exports = { 
clean,
build,
serve,
develop,
compile,
};

文件压缩
useref

const {  src, dest, parallel, series, watch } = require("gulp");
const del = require("del");
const loadPlugins = require("gulp-load-plugins");
const bs = require("browser-sync");
const plugins = loadPlugins();
// const sass = require("gulp-sass");
// const babel = require("gulp-babel");
// const swig = require("gulp-swig");
// const imagemin = require("gulp-imagemin");
const data = { 
menus: [
{ 
name: "Home",
icon: "aperture",
link: "index.html",
},
{ 
name: "Features",
link: "features.html",
},
{ 
name: "About",
link: "about.html",
},
{ 
name: "Contact",
link: "#",
children: [
{ 
name: "Twitter",
link: "https://twitter.com/w_zce",
},
{ 
name: "About",
link: "https://weibo.com/zceme",
},
{ 
name: "divider",
},
{ 
name: "About",
link: "https://github.com/zce",
},
],
},
],
pkg: require("./package.json"),
date: new Date(),
};
// 清除文件
const clean = () => { 
// del 返回的是个 promise
return del(["dist"]);
};
// scss 转 css
const style = () => { 
// 指定从 src 下保留路径
return (
src("src/assets/styles/*.scss", {  base: "src" })
// scss 处理 并保留花括号换行
.pipe(plugins.sass({  outputStyle: "expanded" }))
.pipe(dest("dist"))
.pipe(bs.reload({  stream: true }))
);
};
// 编译脚本文件
const script = () => { 
// 指定从 src 下保留路径
return (
src("src/assets/scripts/*.js", {  base: "src" })
// ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
.pipe(plugins.babel({  presets: ["@babel/preset-env"] }))
.pipe(dest("dist"))
.pipe(bs.reload({  stream: true }))
);
};
// 编译模板文件
const page = () => { 
// src/**/*.html 匹配任意子目录
return src("src/*.html", {  base: "src" })
.pipe(plugins.swig({  data, defaults: {  cache: false } })) // 防止模板缓存导致页面不能及时更新
.pipe(dest("dist"))
.pipe(bs.reload({  stream: true }));
};
// 转换图片文件
const image = () => { 
// 匹配文件下的所有文件
return src("src/assets/images/**", {  base: "src" })
.pipe(plugins.imagemin())
.pipe(dest("dist"));
};
// 转换字体文件, 一般的字体文件不需要压缩等处理, 但是有些svg格式的文件,还是可以稍微处理一下
const font = () => { 
// 匹配文件下的所有文件
return src("src/assets/fonts/**", {  base: "src" })
.pipe(plugins.imagemin())
.pipe(dest("dist"));
};
const serve = () => { 
watch("src/assets/styles/*.scss", style);
watch("src/assets/scripts/*.js", script);
watch("src/*.html", page);
// 这几个静态资源, 开发过程中没必要构建
// watch('src/assets/images/**', image)
// watch('src/assets/fonts/**', font)
// watch('public/**', public)
watch(
["src/assets/images/**", "src/assets/fonts/**", "public/**"],
bs.reload
);
bs.init({ 
notify: false, // browser-sync 连接提示
port: 2080,
open: true, // 自动打开浏览器窗口
// files: "dist/**", // 监听dist文件变化
server: { 
baseDir: ["dist", "src", "public"],
routes: { 
"/node_modules": "node_modules",
},
},
});
};
//public 原样输出到 dist
const public = () => { 
return src("public/**", {  base: "public" }).pipe(dest("dist"));
};
const useref = () => { 
return src("dist/*.html", {  base: "dist" })
.pipe(plugins.useref({  searchPath: ['dist', '.'] }))
.pipe(plugins.if(/\.js$/, plugins.uglify()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({ 
collapseWhitespace: true,
minifyCss: true,
minifyJs: true
})))
.pipe(dest("release"));
};
// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page);
// 先清空文件夹, 再编译+复制public文件夹  正式打开再处理 静态资源文件
const build = series(clean, parallel(compile, public, image, font));
const develop = series(compile, serve);
module.exports = { 
clean,
build,
serve,
develop,
compile,
useref
};

测试
yarn gulp compile
yarn gulp useref

重新规划合理的构建过程
添加临时文件 tmp 避免读写流冲突(不能读写都是dist 文件)

const {  src, dest, parallel, series, watch } = require("gulp");
const del = require("del");
const loadPlugins = require("gulp-load-plugins");
const bs = require("browser-sync");
const plugins = loadPlugins();
// const sass = require("gulp-sass");
// const babel = require("gulp-babel");
// const swig = require("gulp-swig");
// const imagemin = require("gulp-imagemin");
const data = { 
menus: [
{ 
name: "Home",
icon: "aperture",
link: "index.html",
},
{ 
name: "Features",
link: "features.html",
},
{ 
name: "About",
link: "about.html",
},
{ 
name: "Contact",
link: "#",
children: [
{ 
name: "Twitter",
link: "https://twitter.com/w_zce",
},
{ 
name: "About",
link: "https://weibo.com/zceme",
},
{ 
name: "divider",
},
{ 
name: "About",
link: "https://github.com/zce",
},
],
},
],
pkg: require("./package.json"),
date: new Date(),
};
// 清除文件
const clean = () => { 
// del 返回的是个 promise
return del(["tmp"]);
};
// scss 转 css
const style = () => { 
// 指定从 src 下保留路径
return (
src("src/assets/styles/*.scss", {  base: "src" })
// scss 处理 并保留花括号换行
.pipe(plugins.sass({  outputStyle: "expanded" }))
.pipe(dest("tmp"))
.pipe(bs.reload({  stream: true }))
);
};
// 编译脚本文件
const script = () => { 
// 指定从 src 下保留路径
return (
src("src/assets/scripts/*.js", {  base: "src" })
// ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
.pipe(plugins.babel({  presets: ["@babel/preset-env"] }))
.pipe(dest("tmp"))
.pipe(bs.reload({  stream: true }))
);
};
// 编译模板文件
const page = () => { 
// src/**/*.html 匹配任意子目录
return src("src/*.html", {  base: "src" })
.pipe(plugins.swig({  data, defaults: {  cache: false } })) // 防止模板缓存导致页面不能及时更新
.pipe(dest("tmp"))
.pipe(bs.reload({  stream: true }));
};
// 转换图片文件
const image = () => { 
// 匹配文件下的所有文件
return src("src/assets/images/**", {  base: "src" })
.pipe(plugins.imagemin())
.pipe(dest("dist"));
};
// 转换字体文件, 一般的字体文件不需要压缩等处理, 但是有些svg格式的文件,还是可以稍微处理一下
const font = () => { 
// 匹配文件下的所有文件
return src("src/assets/fonts/**", {  base: "src" })
.pipe(plugins.imagemin())
.pipe(dest("dist"));
};
const serve = () => { 
watch("src/assets/styles/*.scss", style);
watch("src/assets/scripts/*.js", script);
watch("src/*.html", page);
// 这几个静态资源, 开发过程中没必要构建
// watch('src/assets/images/**', image)
// watch('src/assets/fonts/**', font)
// watch('public/**', public)
watch(
["src/assets/images/**", "src/assets/fonts/**", "public/**"],
bs.reload
);
bs.init({ 
notify: false, // browser-sync 连接提示
port: 2080,
open: true, // 自动打开浏览器窗口
// files: "dist/**", // 监听dist文件变化
server: { 
baseDir: ["tmp", "src", "public"],
routes: { 
"/node_modules": "node_modules",
},
},
});
};
//public 原样输出到 dist
const public = () => { 
return src("public/**", {  base: "public" }).pipe(dest("dist"));
};
const useref = () => { 
return src("tmp/*.html", {  base: "tmp" })
.pipe(plugins.useref({  searchPath: ['tmp', '.'] }))
.pipe(plugins.if(/\.js$/, plugins.uglify()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({ 
collapseWhitespace: true,
minifyCss: true,
minifyJs: true
})))
.pipe(dest("dist"));
};
// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page);
// 先清空文件夹, 再编译+复制public文件夹  正式打开再处理 静态资源文件
const build = series(clean, parallel(series(compile, useref), public, image, font));
const develop = series(compile, serve);
module.exports = { 
build,  // 正式打包
develop // 开发环境
};

配置一下 npm scripts 脚本

本文地址:https://blog.csdn.net/qinshengnan520/article/details/111133256