疯狂的技术宅

以前出于工作目的,编写和翻译了大量的技术文章,以前端为主,删掉了过时的、毫无营养的内容,留下的都是精华。


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于本站

  • 回到主站

  • 搜索

分析 gulp 的运作方式

时间: 2020-12-22 分类: 前端技术   字数: 1007 字 阅读: 3分钟
标签: #gulp# #vinyl# #stream#

要说到 gulp 的运作方式,就不得不提到 vinyl 和 Node.js 的 stream

vinyl

vinyl 是 gulp 所使用的虚拟的文件格式,在它的自述文件是这么说的:“当提到文件时你首先想到的是什么?肯定是路径和内容吧”,它主要记录的信息有:

  • path:文件路径
  • contents:文件内容
  • cwd:程序执行的目录
  • base:用 glob 寻找文件时开始的目录,例如 src/**/*.js,那 base 就会是 src,这可以用来重现目录结构

另外它还有几个函数用来判断这个文件的内容是什么类型的这类操作,到于这个虚拟文件实际上用在什么地方,咱们稍后再说,先创建一个文件试试:

const { readFile } = require('fs/promises')
const Vinyl = require('vinyl')

const file = new Vinyl({
  path: __filename, // 这个文件的路径
  // 在 Node.js 14.8.0 中 支持 top level await,不过还是建议用 async function 封装
  contents: await readFile(__filename),
  cwd: process.cwd(), // 不设定的话默认值为 process.cwd()
  base: process.cwd(), // 不设定的话默认值为 process.cwd()
})

console.log(file) // 这是应该能看到 <File "file.js" <Buffer ...>>

这样就创建好了一个 gulp 用的文件格式,接下来是 Node.js 的 stream。

stream

stream 设计的本意是要处理大文件的,它能一次读取文件的一小部分,然后再传给调用者进行处理:

const { createReadStream } = require('fs')

// 创建一个读取文件的 stream
const stream = createReadStream(__filename)

// 设置文件字符集编码,否则就会以 Buffer (二进制数据) 的格式读取
stream.setEncoding('utf-8')

// 处理数据
stream.on('data', (chunk) => {
  console.log('chunk', JSON.stringify(chunk))
})

// 结束
stream.on('end', () => {
  console.log('end')
})

实际上它是基于 EventEmitter 之上创建的一组 API,比如 on 就是来自于 EventEmitter,只要照着它的模式,也不一定只能传小块的文件,在 Node.js 中的 stream 也有一个对象模式,如果传的数据不是缓冲区或流就应该设置为对象模式,而对象模式跟一般的模式主要的区别就是不需要处理字符集编码。

再回到 gulp,还记得之前说过 src 是回传一个 stream 吗?接下来看看里面到底传的是什么,先写个 gulpfile 来试看看:

exports.stream = function () {
  const stream = src('./src/**.js')
  stream.on('data', (data) => {
    console.log(data)
  })
  return stream
}

输出:

<File "file.js" <Buffer ...>>

没错,这就是 Vinyl 的文件,gulp 用 stream 的对象模式在传输这些文件,plugin 其实上就是回传一个 Transform 的 stream(Node.js 中 stream 的一种,stream 的种类有 Readable、Writeable、Duplex、Transform)来转换这些文件,比下面是一个把文件内容都换成大写的流:

const { Transform } = require('stream')

exports.uppercase = function () {
  return src('./src/**.js')
    .pipe(
      new Transform({
        // 设置为 object mode
        objectMode: true,
        transform(file, _enc, cb) {
          // 把文件内容转换成为字符串
          const content = file.contents.toString()
          // 转为大写后再转回 Buffer 存回去
          file.contents = Buffer.from(content.toUpperCase())
          // 用 callback 回传
          cb(null, file)
        },
      })
    )
    .pipe(dest('upper'))
}

现在我们有了一个把文件全转大写的 plugin了,不过没什么实用上的意义。这样转来转去的效率太低了。

剩下的部分就是 gulp 处理任务的注册与依赖性的逻辑了,依赖性主要是由 undertaker 处理的,不过我觉得这里没什么特别的东西,所以有兴趣就自己去看看吧。

标签: #gulp# #vinyl# #stream#

标题:分析 gulp 的运作方式

链接:https://fe-tech.viewnode.com/post/202012/22/

作者:疯狂的技术宅

声明: 本博客文章除特别声明外,均采用 CC BY-NC-ND 4.0 国际许可协议( 知识共享署名-非商业性使用-禁止演绎 4.0),转载请注明出处!

TypeScript 高级类型总结
2020 年 Chrome 开发者峰会的亮点
  • 文章目录
  • 站点概览
疯狂的技术宅

疯狂的技术宅

退休程序员,硬件发烧友,人工智能爱好者。写写代码喝喝茶,晒晒太阳带带娃。

457 日志
8 分类
583 标签
GitHub
友情链接
  • viewnode
  • mofish
标签云
  • Javascript 172
  • Node.Js 62
  • Vue 36
  • Typescript 28
  • 实战项目 28
  • 面试 21
  • React 20
  • Css 17
  • 面试题 16
  • 教程 13
  • Promise 12
  • Chrome 9
  • Debug 9
  • 调试 9
  • 资源 9
  • Deno 8
  • Dom 8
  • 杂谈 8
  • 正则表达式 8
  • 测试 8
  • vinyl
  • stream
© 2018 - 2022 疯狂的技术宅 All Rights Reserved
Powered by - Hugo v0.99.0 / Theme by - NexT
Storage by 俺的服务器 / 冀ICP备2022010157号
0%