Gulp 基础与原理

CodeRoverPro
• 阅读 6421

欢迎来我的博客阅读:《Gulp 基础与原理》

Gulp 概述

Gulp 是基于 NodeJS 的项目,一个用作自动化构建的工具,业界一般用来建造前端的工作流。

它的核心原理其实很简单,最主要是通过各种 Transform Stream 来实现文件的处理,然后再进行输出。Transform Streams 是 NodeJS Stream 的一种,是可读又可写的,它会对传给它的对象做一些转换的操作。

文件输入 → Gulp 插件处理 → 文件输出

原则上,gulp 可以针对文件做任何有趣、有创造力事情。
而自动化构建,只是大家主要比较喜欢使用的方向。

Gulp 的特点:

  • 自动化 - Gulp 为你的工作流而服务,自动运行那些费事费力任务。

  • 平台透明 - Gulp 被集成到各种 IDE 中,并且除了 NodeJS 之外,其他如 PHP、.NET、Java 平台都可以使用 Gulp。

  • 强大生态系统 - 你可以使用 npm 上 2000+ 的插件来构造你的工作流。

  • 简单 - Gulp 只提供几个 API,这可以很快地学习和上手。

使用 Gulp

安装

$ npm install gulp-cli -g // 全局安装 Gulp 命令行工具
$ npm install gulp -D // 在项目中,作为 devDependencies 依赖安装 gulp

Gulpfile.js

在使用 CLI 工具的时候,会执行该文件,它是一个可执行的 NodeJS 文件。原理上,你可以在里面运行任何 NodeJS 代码,然后通过调用 gulp 提供的 API,来执行 gulp 任务。
gulpfile.js 文件一般都会放在项目的根目录中。

一个使用 gulp-babel 插件来支持 es2015 语法的案例:

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

gulp.task('default', () => {
    gulp.src('src/app.js')
        .pipe(babel({
            presets: ['es2015']
        }))
        .pipe(gulp.dest('dist'));
});

基本概念与原理

了解这些概念,对于了解 Gulp 的工作原理,和 API 的使用是很有帮助的。

认识 Glob

Glob 是一种用来匹配路径与文件的模式。有点类似于正则表达式,但是语法又有点差异。
这种模式,被广泛用于命令行、Shell 等场景,大家熟悉的 .gitignore 文件也是使用这种模式。

各大语言都有对于 Glob 的实现,例如 Go 和 PHP 的 Glob 函数,Python 中的 glob 模块。
而 NodeJS 的实现是 minimatch, 而在 Gulp 源码中,就用了对 minimatch 进行封装的 node-glob 模块。
Gulp 的 API gulp.watchgulp.src 都有用到 Glob 来匹配对应的路径和文件。
下面是部分语法:

  • *
    匹配该路径段中 0 个或多个任意字符,

如:js/*.js, 匹配 js 目录下的所有 js 文件

  • ?
    匹配该路径段中 1 个任意字符,

如:js/?.js,匹配 js 目录下所有名字只有 1 个字的 js

  • [...]
    匹配该路径段中在指定范围内字符,

如:js/a[0-3].js,匹配 js 目录下 a 开头,第二个字符为 0-3 之间( 包括0和3 )的 js( a03.js不能被匹配到 )

  • !(pattern|pattern|pattern)
    匹配除所给出的模型以外的情况,

如:js/!(a|b).js,匹配 js 目录下名字中不包含 a ,也不包含 b 的所有文件.

  • ?(pattern|pattern|pattern)
    匹配所给出的模型中的 0 个或任意 1 个,

如:js/?(a|a2|b).js, 匹配 js 目录下 a.js , a2.js , b.js

  • +(pattern|pattern|pattern)
    匹配所给出的模型中的 1 个或者多个,

如:js/+(a|a1|b).js, 匹配 js 目录下 a.js , a1.js , b.js , 或者 a, a1, b 这几个字符的组合的 js , 比如 ab.js

  • *(pattern|pattern|pattern)
    匹配所给出的模型中的 0 个或多个或任意个的组合.

如:js/*(a|a1|b).js,匹配 js 目录下 a.js, a1.js, b.js 或者 a, a1, b这几个字符的组合的 js , 比如 ab.js

  • @(pattern|pat*|pat?erN)
    匹配所给出的模型中的任意 1 个,

如:js/@(a|a1|b), 匹配 js 目录下的 a.js, a1.js, b.js

  • **
    * 一样可以匹配任何内容,但 **不仅匹配路径中的某一段,而且可以匹配 a/b/c 这样带有 / 的内容,所以,它还可以匹配子文件夹下的文件.

如:js/**/*.js,匹配 js 目录下及子文件夹中所有的 js 文件。

更多 Glob 的知识和语法,可以参考:
Glob - Wiki
Glob Primer

认识 Vinyl

Vinyl 是 Gulp 自创的一种用来描述一个虚拟文件的类,其中主要包括文件的内容和文件的路径两大信息。vinyl 模块,只是提供了一个类,而实现却交由 vinyl-fs

Vinyl-fs,它主要的工作是接受 glob 模式的参数,然后读取匹配的文件。然后利用 Vinyl 制作一个 Transform Stream,称为 Vinyl Stream 对象,并返回。

在 Gulp 中的 API gulp.srcgulp.watchgulp.dest 都返回一个 Vinyl Stream 实例对象。Vinyl Stream 实例之间可以通过管道( vinyl1.pipe(vinyl2) )的形式来互相传输数据。

从 Gulp 的 源码 中也能看出,这三个 API 都是由 vinyl-fs 提供全部的实现。

再一点是,从这两个模块的实现来看,Gulp 是把文件内容以 Buffer 的形式读到内存中,然后再进行处理的。

认识 Orchestrator

Orchestartor,为 gulp.task 提供了全部实现,这可以从 源码 中看出。
它为 Gulp 提供了任务相关的功能,包括任务注册、任务执行以及相对应的任务进度、错误监控等功能。

Orchestartor 模块,只提供了一个 Orchestartor 类,该类的实例维护着一个 tasks 数组,该数组的内容就是一个我们使用 gulp.task 时注册的函数列表,以及函数的依赖和名字。
通过 源码 中,可以看到 tasks 的数据结构:

...
this.tasks[name] = {
  fn: fn,   // 任务的函数体
  dep: dep,   // 任务所依赖的其他任务名称
  name: name  // 该任务的名称
};
...

Gulp 核心 API

  • gulp.src:获取文件

  • gulp.dest:写入文件

  • gulp.tasks:注册任务

  • gulp.watch:监控文件的改动

gulp.src

gulp.src( globs [, options] )

接收一个 globs 模式的对象,可以是 Array 或者 String,返回一个 Vinyl Stream 实例。
而 options 有下面的值:

  • buffer - Boolean, 控制 file.contents 是返回 buffer 还是 stream。

  • read - Boolean,控制是否读取文件,如果 false,则 file.contentsnull

  • base - String,控制 glob 的 base,默认值是 glob 所有表达式的前置,例如 client/js/**/*.js, base 值就为 client/js/。而 glob 在保存输出路径的时候,取的是 base 之后的路径。所以可以通过该值,来进行输出路径的改写。

gulp.dest

gulp.dest( path [, options] )

接收输出路径,返回一个 Vinyl Stream 实例。
而 options 有以下的值:

  • cwd - String, 默认值 process.pwd(),输出目录的 cwd 参数,只在所给的输出目录是相对路径时候有效。

  • mode - String,八进制权限字符,用以定义所有在输出目录中所创建的目录的权限。

gulp.task

gulp.task( name [, deps ], fn )

定义一个使用 Orchestrator 实现的任务(task)。
参数的描述如下:

  • name - 任务名称

  • deps - 是当前定义的任务需要依赖的其他任务,为一个数组。当前定义的任务会在所有依赖的任务执行完毕后才开始执行。如果没有依赖,则可省略这个参数

  • fn - 为任务函数,我们把任务要执行的代码都写在里面。该参数也是可选的。

gulp.watch

gulp.watch( glob [, opts ], tasks )
or
gulp.watch( glob [, opts, cb ] )

用来监视文件的变化,当文件发生变化后,我们可以利用它来执行相应的任务。
各参数的描述如下:

  • glob - 为要监视的文件 Glob 匹配模式。

  • opts - 为一个可选的配置对象。

  • tasks - 为文件变化后要执行的任务,为一个数组

常用插件

更多插件,可以搜索官方插件库

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(