系统化学习前端之gulp

gulp 是什么

基于流的自动化构建工具

gulp 单任务

gulp 执行单个任务可以直接通过定义任务,执行任务名方式来完成任务。

gulp4.0 之前

  1. 安装依赖

    npm install -D gulp
    
  2. 配置文件 gulpfile.js

    具名任务

    1. 定义任务

      const gulp = require('gulp')
      
      gulp.task('job', (cb) => {
        console.log('job')
        cb()
      })
      
    2. 执行 gulp 指令

      npx gulp job
      

    不具名任务

    1. 定义任务

      const gulp = require('gulp')
      
      gulp.task('default', (cb) => {
        console.log('default')
        cb()
      })
      
    2. 执行 gulp 指令

      npx gulp
      

gulp4.0 之后

  1. 安装依赖

    npm install -D gulp
    
  2. 配置文件 gulpfile.js

    具名任务

    1. 定义任务

      const job = (cb) => {
        console.log('job')
        cb() // 使用回调结束 task,不使用回调会导致报错 task not complete
      }
      
      module.exports = {
        job
      }
      
    2. 执行 gulp 指令

      npx gulp job
      

    不具名任务

    1. 定义任务

      const job = (cb) => {
        console.log('default')
        cb()
      }
      
      module.exports.default = job
      
    2. 执行 gulp 指令

      npx gulp
      

    注意:每个 gulp 任务都是一个异步 JavaScript 函数,任务结束需要满足以下任一条件:

    1. 任务函数可以接收一个 callback 作为参数,调用回调函数则任务结束。
    2. 任务函数返回 stream, promise, event emitter, child process 或 observable 类型的函数则任务结束。

gulp 多任务

gulp 执行多个任务可以通过 gulp 内置 api 来进行任务组合执行,gulp 任务组合 api 有 series 和 parallel,两者均可以接收任意数量的任务函数或者组合后的任务组合。

series

串行任务组合。series() 接收的任务函数或者任务组合会按照串行执行,即同一时间只执行单个任务,当上一个任务完成再执行下一个任务。

  1. 定义任务

    const { series, parallel } = require('gulp')
    
    const task1 = (cb) => {
      setTimeout(() => {
        console.log('task1')
        cb()
      }, 1000)
    }
    
    const task2 = (cb) => {
      setTimeout(() => {
        console.log('task2')
        cb()
      }, 1000)
    }
    
    const task3 = (cb) => {
      setTimeout(() => {
        console.log('task3')
        cb()
      }, 1000)
    }
    
    module.exports.default = series(task1, task2, task3)
    
  2. 执行指令

    npx gulp
    

parallel

并行任务组合。parallel() 接收的任务函数和任务组合会按照并行执行,即同一时间执行多个 parallel 接收的任务。

  1. 定义任务

    const { series, parallel } = require('gulp')
    
    const task1 = (cb) => {
      setTimeout(() => {
        console.log('task1')
        cb()
      }, 1000)
    }
    
    const task2 = (cb) => {
      setTimeout(() => {
        console.log('task2')
        cb()
      }, 1000)
    }
    
    const task3 = (cb) => {
      setTimeout(() => {
        console.log('task3')
        cb()
      }, 1000)
    }
    
    module.exports.default = parallel(task1, task2, task3)
    
  2. 执行指令

    npx gulp
    

series / parallel 复合

  1. 定义任务

    const { series, parallel } = require('gulp')
    
    const task1 = (cb) => {
      setTimeout(() => {
        console.log('task1')
        cb()
      }, 1000)
    }
    
    const task2 = (cb) => {
      setTimeout(() => {
        console.log('task2')
        cb()
      }, 1000)
    }
    
    const task3 = (cb) => {
      setTimeout(() => {
        console.log('task3')
        cb()
      }, 1000)
    }
    
    const seriesTask = series(task1, task2, task3)
    
    const parallelTask = parallel(task1, task2, task3)
    
    const composeTask = series(seriesTask, parallelTask)
    
    module.exports.default = composeTask
    
  2. 执行指令

    npx gulp
    

读取/写入文件

gulp 定义任务,执行任务都是在 gulp 配置文件中操作的。实际项目处理,gulpfile.js 读取外部文件,处理后返回并写入文件,因此,需要使用 gulp 读取和写入文件 api 来处理外部文件,gulp 读取、写入文件 api 分别为 src 和 dest。

src

src 接收文件路径作为参数,以 stream 的方式读取文件。单个文件路径以字符串形式接收,多个文件路径以数组方式接收。

文件路径可以以正则形式进行匹配,至少有一个匹配,否则报错。

匹配规则:

1. `/src/*.js`

	表示仅匹配 src 目录下的所有js,对于 /src/js/ 目录下的 js 是无法匹配的。

2. `/src/**/*.js`

	表示匹配 src 目录下的所有js,包含 /src/js/ 目录下的 js 。

3. `[ '/src/**/*.js', '!script/' ]`

	表示匹配 src 目录下的所有js,包含 /src/js/ 目录下的 js ,但不包含 /src/script/ 目录下的 js 。

dest

dest 接收输入目录作为参数,将 stream 写入到文件中。

src/dest 用法

  1. 文件结构

    main.js

    const sum = (x, y) => {
      return x + y
    }
    
    const res = sum(x, y)
    console.log(res)
    

    gulpfile.js

    const { src, dest } = require('gulp')
    const babel = require('gulp-babel')
    const uglify = require('gulp-uglify')
    
    const job = (cb) => {
      return src('./src/*.js')
      .pipe(babel({ presets: ['@babel/preset-env'] }))
      .pipe(uglify())
      .pipe(dest('./dist/'))
    }
    
    module.exports.default = job
    
  2. 安装 gulp 插件及依赖

    npm install -D gulp-babel @babel/core @babel/preset-env
    npm install -D gulp-uglify
    
  3. 启动 gulp

    npx gulp
    

    注意: src,dest读取和写入文件均是以 stream 流的方式进行的。

    1. pipe 顾名思义:管道,用于”运输“ stream 流,对 stream 流进行处理以后,传递给下一个pipe。

    2. gulp-babel 插件,用于 ES6 语法转换为 ES5。

    3. gulp-uglify 插件,用于压缩 js 文件。

监听文件

开发过程中,js 文件一旦发生修改,gulp 需要重新启动才能进行 stream 流的处理操作。gulp 提供了一个监听文件内容变化的 api ,用于监听文件,一旦内容变化,则原有任务会重新执行。监听文件变化的 api 是 watch 。

watch

watch 接收两个参数,一个是需要监听的文件路径,同样可以使用正则匹配;另一个是文件内容变化需要执行的任务或任务组合。

gulpfile.js

const { src, dest, watch } = require('gulp')
const babel = require('gulp-babel')
const uglify = require('gulp-uglify')

const job = (cb) => {
  return src('./src/*.js')
  .pipe(babel({ presets: ['@babel/preset-env'] }))
  .pipe(uglify())
  .pipe(dest('./dist/'))
}

watch('./src/*.js', job)

module.exports.default = job

项目简单配置案例

demo项目地址

gulpfile.js

const { series, parallel, src, dest, watch } = require('gulp')

const htmlMin = require('gulp-htmlmin')

const less = require('gulp-less')
const postCss = require('gulp-postcss')
const postPresetEnv = require('postcss-preset-env')
const cssMin = require('gulp-cssmin')

const babel = require('gulp-babel')
const uglify = require('gulp-uglify')

const inject = require('gulp-inject')

const browser = require('browser-sync')

const clean = require('gulp-clean')

const htmlTask = () => {
  return src('./src/index.html')
  .pipe(htmlMin({
    collapseWhitespace: true // 压缩 html
  }))
  .pipe(dest('./dist/'))
}

const cssTask = () => {
  return src('./src/css/**/*.less', { base: './src' }) // 保持对应目录结构不变
  .pipe(less()) // 处理 less
  .pipe(postCss([postPresetEnv()])) // 自动增加浏览器前缀
  .pipe(cssMin()) // 压缩 css
  .pipe(dest('./dist/'))
}

const jsTask = () => {
  return src('./src/js/**/*.js', { base: './src' }) 
  .pipe(babel({ presets: ['@babel/preset-env'] })) // 编译 ES6 -> ES5
  .pipe(uglify()) // 压缩 js
  .pipe(dest('./dist/'))
}

const injectTask = () => {
  return src('./dist/index.html')
  .pipe(
    inject(
      src(['./dist/**/*.js','./dist/css/**/*.css'], { read: false }),
      { relative: true } // 相对路径引入
    )
  )
  .pipe(dest('./dist/'))
}

// 搭建本地服务器
const server = browser.create()
const serverTask = () => {

  watch("./src/*.html", series(htmlTask, injectTask))
  watch("./src/**/*.less", series(cssTask, injectTask))
  watch("./src/**/*.js", series(jsTask, injectTask))

  server.init({
    port: 3000,
    open: true,
    files: './dist/*',
    server: {
      baseDir: './dist/'
    }
  })
}

// 清空 dist 目录
const cleanTask = () => {
  return src('dist')
  .pipe(clean())
}

const buildTask = series(cleanTask, parallel(htmlTask, cssTask, jsTask), injectTask)
const devTask = series(buildTask, serverTask)

module.exports = {
  devTask,
  buildTask
}

package.json

{
    "scripts": {
        "dev": "gulp devTask",
        "build": "gulp buildTask",
  },
}

更多配置可以查看 gulp 插件配置

posted @ 2023-02-22 15:50  深巷酒  阅读(36)  评论(0编辑  收藏  举报