什么是Gulp?

一个工具包,可以帮你自动化和增强你的工作流。

Gulp和Webpack的区别

gulp的核心理念是 task runner

  • 可以定义自己的一系列任务,等待任务被执行
  • 基于文件Stream的构建流
  • 我们可以使用gulp的插件体系来完成某些任务

webpack的核心理念是 module bundler

  • webpack是一个模块化的打包工具
  • 可以使用各种各样的loader来加载不同的模块
  • 可以使用各种各样的插件在 webpack 打包的生命周期完成其他的任务

gulp现在常用于做一些自动化任务,比如将打包好的项目文件上传到服务器这种。

gulp相对于webpack的优缺点:

  • gulp相对于webpack思想更加的简单、易用,更适合编写一些自动化的任务
  • 但是目前对于大型前端项目(Vue、React、Angular)并不会使用gulp来构建,比如默认gulp是不支持模块化的

    Gulp的基本使用

  1. 安装

npm install gulp

  1. 新建gulpfile.js ```javascript const gulp = require(“gulp”);

// 定义任务 const foo = (cb) => { console.log(“foo”); cb(); };

// gulp4之前的使用方式 gulp.task(“bar”, (cb) => { console.log(“bar”); cb(); });

module.exports = { foo, };

// 默认任务 module.exports.default = (cb) => { console.log(“default task”); cb(); };

  1. 3. 运行
  2. `npx gulp foo`<br />想要执行 foo 函数,就输入上面的,如果想执行 bar 函数,就输入 `npx gulp bar`
  3. <a name="jjVAp"></a>
  4. # 创建gulp任务
  5. 每个gulp任务都是一个异步的JavaScript函数:
  6. - 此函数可以接受一个callback作为参数,调用callback函数那么任务会结束
  7. - 或者是一个返回 streampromiseevent emitterchild processobservale类型的函数
  8. 任务可以是public或者private类型的:
  9. - 公开任务(Public tasks)从gulpfile中被导出(export),可以通过gulp命令直接调用
  10. - 私有任务(Private tasks)被设计为在内部使用,通常作为series() parallel() 组合的组成部分
  11. <a name="dlDud"></a>
  12. # 任务组合series和parallel
  13. gulp提供了两个强大的组合方法:
  14. - series():串行任务组合
  15. - parallel():并行任务组合
  16. - 他们都可以接受任意数量的任务函数或者已经组合的操作
  17. 也可以对组合后的任务再次进行组合
  18. ```javascript
  19. const { series, parallel } = require("gulp");
  20. const task1 = (cb) => {
  21. setTimeout(() => {
  22. console.log("task1");
  23. cb();
  24. }, 2000);
  25. };
  26. const task2 = (cb) => {
  27. setTimeout(() => {
  28. console.log("task2");
  29. cb();
  30. }, 2000);
  31. };
  32. const task3 = (cb) => {
  33. setTimeout(() => {
  34. console.log("task3");
  35. cb();
  36. }, 2000);
  37. };
  38. const seriesTask = series(task1, task2, task3);
  39. const parallelTask = parallel(task1, task2, task3);
  40. const composeTask = series(seriesTask, parallelTask);
  41. module.exports = {
  42. composeTask,
  43. };

读取和写入文件

gulp 暴露了 src() 和 dest() 方法用于处理计算机上存放的文件。

  • src() 接受参数,并从文件系统中读取文件然后生成一个Node流(Stream),它将所有匹配的文件读取到内存中并通过流(Stream)进行处理
  • 由src() 产生的流(stream)应当从任务(task函数)中返回并发出异步完成的信号
  • dest() 接受一个输出目录作为参数,并且它还会产生一个Node流(Stream),通过该流将内容输出到文件中

流(stream)所提供的主要的API是 .pipe() 方法,pipe的原理是什么呢?

  • pipe方法接受一个转换流(Transform streams)或可写流(Writable streams)
  • 那么转换流或者可写流,拿到数据之后可以对数据进行处理,再次传递给下一个转换流或者可写流

    gulp文件匹配

src() 方法接受一个 glob 字符串或由多个 glob 字符串组成的数组作为参数,用于确定那些文件需要被操作

  • glob或blog数组必须至少匹配到一个匹配项,否则src()将报错

glob的匹配规则如下:

  • (* 一个星号):在一个字符串中,匹配任意数量的字符,包括零个匹配
  • (** 两个星号):在多个字符串匹配中匹配任意数量的字符串,通常用在匹配目录下的文件
  • (取反!):取反是取相反的值,用法是在匹配值的时候在后面加!进行取反操作

    gulp文件监听

    gulp提供了watch方法,用于监听文件变化 ```javascript const { src, dest, watch } = require(“gulp”);

const babel = require(“gulp-babel”); const terser = require(“gulp-terser”);

const jsTask = () => { // 从src中读取文件,输出到dist文件夹中 return src(“./src/*.js”) .pipe(babel({ presets: [“@babel/preset-env”] })) .pipe(terser({ mangle: { toplevel: true } })) .pipe(dest(“./dist”)); };

watch(“./src/*/.js”, jsTask);

module.exports = { jsTask, };

  1. <a name="R2gWN"></a>
  2. # gulp处理html文件
  3. 1. 安装 gulp-htmlmin 插件
  4. `npm install gulp-htmlmin -d`
  5. 2. 使用插件处理
  6. ```javascript
  7. const { src, dest } = require("gulp");
  8. const htmlMin = require("gulp-htmlmin");
  9. const htmlTask = () => {
  10. return src("./src/*.html")
  11. .pipe(
  12. htmlMin({
  13. collapseWhitespace: true,
  14. })
  15. )
  16. .pipe(dest("./dist"));
  17. };
  18. module.exports = {
  19. htmlTask,
  20. };

gulp处理js文件

处理js文件需要用到的库:

  1. @babel/core
  2. @babel/preset
  3. gulp-babel
  4. gulp-terser ```javascript const { src, dest } = require(“gulp”);

const terser = require(“gulp-terser”); const babel = require(“gulp-babel”);

const jsTask = () => { return src(“./src/js/**.js”, { base: “./src” }) .pipe(babel({ presets: [“@babel/preset-env”] })) .pipe(terser({ mangle: { toplevel: true } })) .pipe(dest(“./dist”)); };

module.exports = { jsTask, };

<a name="pNhbj"></a>
# gulp处理less文件

处理less文件需要用到的库:

1. postcss
1. postcss-preset-env
1. gulp-less
1. gulp-postcss
```javascript
const { src, dest } = require("gulp");

const less = require("gulp-less");
const postcss = require("gulp-postcss");
const postcssPresetEnv = require("postcss-preset-env");

const lessTask = () => {
  return src("./src/css/*.less", { base: "./src" })
    .pipe(less())
    .pipe(postcss([postcssPresetEnv()]))
    .pipe(dest("./dist"));
};

module.exports = {
  lessTask,
};

处理html资源注入

gulp默认处理的文件(css、js等)是不会被引入html文件中的,为了能够实现自动引入到html文件中,我们需要使用插件gulp-inject

  1. 安装插件

npm install gulp-inject -d

  1. gulpfile.js中使用 ```javascript const { src, dest } = require(“gulp”);

const inject = require(“gulp-inject”);

const injectHtml = () => { return src(“./dist/.html”) .pipe( inject(src([“./dist/js/.js”, “./dist/css/*.css”]), { relative: true }) ) .pipe(dest(“./dist”)); };

module.exports = { injectHtml, };


3. html文件中使用

我们还需要对打包出来的dist文件夹下的html文件中做一些配置
```html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- inject:css -->
  <!-- endinject -->
</head>

<body>
  <!-- inject:js -->
  <!-- endinject -->
</body>

</html>

gulp开启本地服务

  1. 安装插件

npm install browser-sync -D

  1. 配置使用 ```javascript const browserSync = require(“browser-sync”);

// 搭建本地服务器 const bs = browserSync.create(); const serve = () => { watch(“./src/.html”, series(htmlTask, injectHtml)); watch(“./src/js/.js”, series(jsTask, injectHtml)); watch(“./src/css/.less”, series(lessTask, injectHtml)); bs.init({ port: 8888, open: true, files: “./dist/“, server: { baseDir: “./dist”, }, }); };

<a name="iauPT"></a>
# serve和build组合

1. 安装 clean 插件,用于清除上次打包的数据
```javascript
const { src, dest, watch, series, parallel } = require("gulp");

const htmlMin = require("gulp-htmlmin");
const terser = require("gulp-terser");
const babel = require("gulp-babel");
const less = require("gulp-less");
const postcss = require("gulp-postcss");
const postcssPresetEnv = require("postcss-preset-env");
const inject = require("gulp-inject");
const browserSync = require("browser-sync");
const del = require("del");

const htmlTask = () => {
  return src("./src/*.html", { base: "./src" })
    .pipe(
      htmlMin({
        collapseWhitespace: true,
      })
    )
    .pipe(dest("./dist"));
};

const jsTask = () => {
  return src("./src/js/**.js", { base: "./src" })
    .pipe(babel({ presets: ["@babel/preset-env"] }))
    .pipe(terser({ mangle: { toplevel: true } }))
    .pipe(dest("./dist"));
};

const lessTask = () => {
  return src("./src/css/*.less", { base: "./src" })
    .pipe(less())
    .pipe(postcss([postcssPresetEnv()]))
    .pipe(dest("./dist"));
};

const injectHtml = () => {
  return src("./dist/*.html")
    .pipe(
      inject(src(["./dist/js/*.js", "./dist/css/*.css"]), { relative: true })
    )
    .pipe(dest("./dist"));
};

// 搭建本地服务器
const bs = browserSync.create();
const serve = () => {
  watch("./src/*.html", series(htmlTask, injectHtml));
  watch("./src/js/*.js", series(jsTask, injectHtml));
  watch("./src/css/*.less", series(lessTask, injectHtml));
  bs.init({
    port: 8888,
    open: true,
    files: "./dist/*",
    server: {
      baseDir: "./dist",
    },
  });
};

const clean = () => {
  return del(["dist"]);
};

const buildTask = series(
  clean,
  parallel(htmlTask, jsTask, lessTask),
  injectHtml
);

const serveTask = series(buildTask, serve);
module.exports = {
  buildTask,
  serveTask,
};

总结

gulp的本质就是一个用来处理文件流的工具。它可以处理项目中不同类型的文件,原本这一工作需要python或者shell或者nodeJs这种能够操作本地文件的语言或脚本来实现,gulp相当于是基于node提供了一些专门用于处理文件的api,相较于使用其他语言对于前端来说更好上手。