美文网首页
Gulp4(一)——基本使用及核心原理

Gulp4(一)——基本使用及核心原理

作者: 顽皮的雪狐七七 | 来源:发表于2021-01-01 13:05 被阅读0次

    目录

    • Glup
      • Gulp的使用步骤
      • Gulp的基本使用
        • 安装
        • 起步
        • 默认任务
        • gulp4.0之前的任务注册
        • Gulp的组合任务
        • Gulp的异步任务
          • 回调方式去解决
          • stream
      • Gulp构建过程核心工作原理
      • Gulp读取流和写入流的API

    之前写过一个4.0之前版本的gulp,这里引用一下 Gulp(4.0之前旧版本)——自动化的流程构建工具 ,不过可以不用看,直接看下面的就行。

    Glup

    特点就是高效、易用。使用Gulp开发很简单。

    Gulp的使用步骤

    1. 在项目中安装一个Gulp的开发依赖
    2. 在根目录下添加一个gulpfile.js文件,用于编写一些需要Gulp自动构建的一些任务
    3. 在命令行中通过cli去运行这些任务

    Gulp的基本使用

    安装

    npm i gulp
    

    起步

    1. 创建一个gulpfile.js的文件,这是个gulp的入口文件
    2. 在文件中创建任务

    PS: 在最新的gulp中,取消了同步代码模式,约定每一个任务都是异步任务,当任务完成过后要标记任务完成。否则会报错

    // gulpfile.js
    exports.foo = () => {
      console.log("foo task working~")
    }
    
    // 运行的时候虽然正常输出但是会报错,是否忘记添加结束?
    // Starting 'foo'...
    // foo task working~
    // The following tasks did not complete: foo
    // Did you forget to signal async completion?
    

    添加参数done表示任务结束

    // gulpfile.js
    exports.foo = done => {
      console.log("foo task working~")
      done() // 标识任务完成
    }
    
    1. 命令行运行
    gulp foo
    # Using gulpfile E:\professer\Gulp\gulpfile.js
    # Starting 'foo'...
    # foo task working~
    # Finished 'foo' after 2.43 ms
    

    默认任务

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

    运行的时候不需要指定任务

    gulp    
    # Using gulpfile E:\professer\Gulp\gulpfile.js
    # Starting 'default'...
    # default task working~
    # Finished 'default' after 3.03 ms
    

    gulp4.0之前的任务注册

    gulp4.0以前,我们注册任务需要在gulp模块的一个方法中实现

    const gulp = require("gulp")
    
    gulp.task('bar', done => {
      console.log('bar working~')
      done()
    })
    

    虽然4.0之后还可以使用,但是这种方式已经不被推荐了。更推荐大家使用导出函数成员的方式去定义gulp任务。

    Gulp的组合任务

    gulp模块中的series, parallelAPI可以轻松创建组合任务分别执行串行任务并行任务

    // 引入串行并行方法
    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.hello1 = series(task1, task2, task3)
    
    // 并行的任务结构
    exports.hello2 = parallel(task1, task2, task3)
    

    命令行运行

    gulp hello1
    # 可以看到先执行了task1结束后才执行task2,task2结束后才执行task3
    # Using gulpfile E:\professer\Gulp\gulpfile.js
    # Starting 'task1'...
    # task1 working!
    # Finished 'task1' after 1.01 s
    # Starting 'task2'...
    # task2 working!
    # Finished 'task2' after 1 s
    # Starting 'task3'...
    # task3 working!
    # Finished 'task3' after 1.01 s
    # Finished 'hello1' after 3.08 s
    
    gulp hello2
    # 可以看到task1,task2,task3同时开始执行
    # Using gulpfile E:\professer\Gulp\gulpfile.js
    # Starting 'hello2'...
    # Starting 'task1'...
    # Starting 'task2'...
    # Starting 'task3'...
    # task1 working!
    # Finished 'task1' after 1.01 s
    # task2 working!
    # Finished 'task2' after 1.02 s
    # task3 working!
    # Finished 'task3' after 1.02 s
    # Finished 'hello2' after 1.02 s
    
    用途
    • 例如部署项目,先需要执行编译任务,就需要串行任务。
    • 例如cssjs的编译和压缩,彼此互不干扰,就可以使用并行任务。

    Gulp的异步任务

    回调方式去解决
    1. 普通回调
    exports.callback = done => {
      console.log("callback task~")
      done()
    }
    

    这种回调方式和node的是一种,都是错误优先的方式,如果我们要返回一种错误的回调,需要在done中传参数

    exports.callback_error = done => {
      console.log("callback error task~")
      done(new Error('task failed~'))
    }
    

    这个时候运行观察会报出错误,而且之后的任务都不会再继续执行。

    gulp callback_error
    
    # Using gulpfile E:\professer\Gulp\gulpfile.js
    # Starting 'callback_error'...
    # callback error task~
    # 'callback_error' errored after 2.38 ms
    # Error: task failed~
    #     at exports.callback_error (E:\professer\Gulp\gulpfile.js:51:8)
    #     at callback_error (E:\professer\Gulp\node_modules\undertaker\lib\set-task.js:13:15)
    #     at bound (domain.js:427:14)
    #     at runBound (domain.js:440:12)
    #     at asyncRunner (E:\professer\Gulp\node_modules\async-done\index.js:55:18)
    #     at processTicksAndRejections (internal/process/task_queues.js:79:11)
    
    2. promise

    gulp任务还支持接受promise

    exports.promise = () => {
      console.log("promise task~")
      // 这里通过promise的resolve方法返回一个成功的promise
      // 一旦resolve了,那么任务就结束了
      // resolve里面不需要传参数,因为gulp会忽略这个值
      return Promise.resolve()
    }
    

    promise失败怎么办?reject方法就可以

    exports.promise_error = () => {
      console.log("promise task~")
      return Promise.reject(new Error('promise failed'))
    }
    
    3. async/await

    ES7中的asyncawait也可以

    PS:如果node版本是8+就可以使用这种方式

    const delay = time => {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, time)
      })
    }
    exports.async = async () => {
      await delay(1000)
      console.log("async task~")
    }
    

    执行

    gulp async
    # Using gulpfile E:\professer\Gulp\gulpfile.js
    # Starting 'async'...
    # async task~
    # Finished 'async' after 1.01 s
    
    stream

    需要在任务函数中返回一个stream对象

    const fs = require("fs")
    exports.stream = () => {
      // 读取文件的文件流对象
      const readStream = fs.createReadStream('package.json')
      // 写入文件的文件流对象
      const writeStream = fs.createWriteStream('temp.txt')
      // 文件复制从读入通过管道倒入到写入里面
      readStream.pipe(writeStream)
      // 把readStream返回
      return readStream
    }
    

    整个任务完成的时机就是stream对象end的时候。因为stream对象都有一个end事件,文件流读取完成过后,end事件就会执行。gulp就会知道任务已经完成了。

    类似于

    exports.end = done => {
      const readStream = fs.createReadStream('package.json')
      const writeStream = fs.createWriteStream('temp.txt')
      readStream.pipe(writeStream)
      // 监听了end事件执行done
      readStream.on('end', () => {
        done()
      })
    }
    

    Gulp构建过程核心工作原理

    Gulp是一个基于流的构建系统。
    工作原理 就是把文件读取出来,做完操作之后写入到另一个文件中。

    image
    const fs = require("fs")
    const { Transform } = require('stream')
    
    exports.default = () => {
      // 文件读取流
      const read = fs.createReadStream('normalize.css')
      // 文件写入流
      const write = fs.createWriteStream('normalize.min.css')
      // 文件转换流
      const transform = new Transform({
        transform: (chunk, encoding, callback) => {
          // ★★★核心转换过程实现★★★
          // chunk => 读取流中读取到的内容(Buffer)
          // 使用toString将Buffer数组转化成字符串
          const input = chunk.toString()
          // 替换掉空白字符和css注释
          // 将转换后的结果放在output变量中
          const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
          // 执行callback的时候返回,错误优先第一个传错误参数,没有的话传null
          // output是成功之后作为结果导出
          callback(null, output)
        }
      })
      
      // 文件复制从读入通过管道先转换,后倒入到写入里面
      read
        .pipe(transform)
        .pipe(write)
        
      return read
    }
    

    Gulp读取流和写入流的API

    Gulp中专门提供了读取流和写入流的API,比nodeAPI更加强大,更容易使用。转换流大都是通过独立的插件来提供。

    举个栗子:

    1. 加载一个压缩css的插件npm install gulp-clean-css和修改文件类型的插件npm install gulp-rename
    2. gulpfile.js里面写
    const { src, dest} = require('gulp')
    const cleanCss = require('gulp-clean-css')
    const rename = require('gulp-rename')
    
    exports.default = done => {
      // 读取流,参数是文件路径,比较强大的地方是这里可以使用通配符匹配多个文件
      src('src/*.css')
        // 压缩代码
        .pipe(cleanCss())
        // 修改文件类型
        .pipe(rename({ extname: '.min.css'}))
        // 输出流,参数是输出路径
        .pipe(dest('dest'))
      done()
    }
    
    1. 在命令行中运行gulp可以看到对应的文件生成,是压缩过的且名称变成了normalize.min.css

    相关文章

      网友评论

          本文标题:Gulp4(一)——基本使用及核心原理

          本文链接:https://www.haomeiwen.com/subject/kwkjoktx.html