Gulp 入门,就是这么简单

Gulp 入门学习

1. 什么是Gulp

​ Gulp是一款自动化构建工具。怎么理解这句话呢,首先自动化的意思是我们通过编写一些Gulp的配置和任务,Gulp自动帮助我们构建应用。其次构建工具是说Gulp是用来构建项目的,比如对我们前端的JavaScript,CSS,HTML进行打包压缩。从这点来看,它实现的功能是和webpack类似的。那既然有webpack,我们为什么要使用Gulp呢?这是因为,Gulp是侧重流程的,也就是构建的过程。比如,我们需要构建JavaScript和CSS,先构建谁,后构建谁,这个构建的流程我们可以自定定义的。而webpack,它的定位是静态模块打包器,如果从这块来区分的话,那么Gulp就是动态构建工具。

2. 如何使用Gulp
##### 2.1 Gulp使用流程

安装Gulp --------> 创建gulpfile文件 --------> 编写gulpfile.js文件 --------> 运行gulp命令

​ 我们构建任务和流程都是定义在gulpfile文件中的,在我们写好gulpfile文件后,就可以通过gulp命令来执行任务了。

2.2 安装Gulp

​ 安装gulp我们使用如下命令:

npm install --save-dev gulp

​ 安装之后可以在package.json文件中,指定脚本,执行gulp命令:

在这里插入图片描述

​ 如果不通过npm脚本来执行gulp,这个时候再命令行中使用gulp命令,会提示命令找不到,是因为我们没有全局安装gulp,而package.json文件里面的脚本,会自动查找当前项目中*node_modules/.bin/*里面的命令,所以可以自动执行。

​ 如果想要全局使用gulp的话,执行以下命令,全局安装gulp即可:

npm install -g gulp

​ 当然我们也可以安装gulp的客户端工具,使用方式是一样的。

npm install -g gulp-cli

​ 到此,我们的安装完成了,可以创建gulpfile.js配置文件,创建自己的任务了。

2.3 如何创建gulpfile文件
2.3.1 第一种方式

在这里插入图片描述

​ 在项目的根目录下面直接创建一个___gulpfile.js___,然后直接在这里面进行任务和流程的编写。执行gulp命令的时候会自动查找到这个文件。

2.3.1 第二种方式

[

​ 在项目的根目录下面,创建一个名为___gulpfile.js___的___文件夹___,在文件夹里面创建一个___index.js__,这样的话,我们直接执行gulp也会找到这个配置文件。

2.4 编写gulpfile.js文件

​ 在gulpfile.js中,我们需要编写的就是我们需要执行的任务。对于gulp来说,我们的任务,就是一个一个的JavaScript异步函数。这个任务函数可以接受一个回调函数作为参数,这个回调函数是有gulp在执行任务函数的时候传递进来的。当我们的任务函数执行之后,我们需要通知gulp当前的任务是执行成功了,还是执行失败了,gulp根据任务函数的通知来决定是否继续执行或者结束。所以,我们要在任务中返回stream、promise、event emmitter、child process或者ovservable这些类型的值,如果我们不返回这些值,那么必须要执行gulp给任务函数传递的回调函数,否则,gulp则获取不到任务函数的执行结果。

​ __注意:既然我们的任务都是函数,那么我们就可以在函数中做任何事情。我们既可以写一般的JavaScript代码,也可以在函数中使用第三方的模块。当然,我们也可以使用Gulp提供的插件。

​ 我们一起来看个例子,例子的文件名是gulpfile.js,是我们的gulp配置文件:

const {src, dest} = require('gulp');

/**
 * 这个函数返回stream类型的值
 */
function streamTask() {
    return src('./test.js').pipe(dest('output'));
}

/**
 * 这个函数既没有返回stream、promise、event emmitter、child process或者ovservable这些类型的值
 * 也没有调用gulp传入的回调函数
 */
function streamTaskWithoutReturn() {
    src('./test.js').pipe(dest('output'));
}

/**
 * 这个函数执行了gulp传入进来的回调函数
 * @param {*} cb 
 */
function showCallBack(cb) {
    console.log("gulp传递进来的回调函数:" + cb.toString());
    cb();
}

/**
 * 导出了streamTask任务和streamTaskWithoutReturn任务
 * 他们可以在gulp --task中被展示出来
 * 可以使用gulp来执行默认的default任务
 * 可以使用gulp noBack 来执行对应的任务 
 */
exports.default = streamTask;
exports.noBack = streamTaskWithoutReturn;

​ 在这个例子中我们定义了三个任务(Task),每个任务的写法都不太一样。

​ 在第一个任务streamTask中,我们使用了gulp提供的api:srcdest,这两个api会在后面解释,我们重点关注一下任务的返回值,和接收的回调函数。

​ 对于streamTask这个任务,我们在文件底部,通过exports.default将它设置为gulp默认的任务来执行,此时我们在命令行运行gulp命令,它将被执行:

在这里插入图片描述

​ 对于streamTaskWithoutReturn这个任务,我们将它导出为noBack这个名称的任务,我们可以看到它并没有返回stream、promise、event emmitter、child process或者ovservable这些类型之一,也没有接收和使用callback函数,执行的结果如下:

在这里插入图片描述

​ 这个时候,gulp提醒我们noBack这个任务并没有完成,并且提醒我们是否忘记在异步完成的时候发信号了。像这种情况,gulp就不知道我们的任务是否完成了。所以我们在编写任务的时候,一定要返回stream、promise、event emmitter、child process或者ovservable这些类型之一,或者接收并使用callback函数了,就像streamTask或者showCallBack函数一样。

​ 对于第三个任务,showCallBack,我们可以看到,它处理了回调函数,但是并没有在文件底部导出这个任务,这个时候就不能通过*gulp [taskName]*的方式去执行这个任务了。

在这里插入图片描述

​ 如果我们去执行gulp showCallBack,gulp会提示我们,showCallBack这个任务没有被定义。

​ 如果我们在文件底部,导出这个任务,像这样:

在这里插入图片描述

​ 那么,我们就可以通过gulp showCallBack命令去执行这个任务了:

在这里插入图片描述

​ 我们可以看到,任务正常执行了,并且输出了cb这个回调函数,这个函数就是gulp在执行任务的时候给我们传递的回调函数,它会移除监听,并做退出操作,这样gulp就能正常执行任务,并且可以获取任务的执行状态了。像上面这个例子,没有被导出的任务叫做__私有任务__,只能够在gulpfile.js里面使用,不能被外部使用,而通过exports导出的任务叫做__公开任务__,可以直接被gulp使用。

​ 至此,我们应该学会了如何编写gulp的单独任务。针对以上的返回类型,需要提及一下,async await函数。我们的任务也可以通过async await函数去编写,因为它会用promise对任务进行包装。大家对以上返回的类型,可能不都了解,等我吗学习完Gulp的API我们就理解了。

​ 我们说gulp在做构建的时候更偏向于流程,接下来,我们看看gulp是如何控制构建流程的。

​ 如果我们有很多个零散的任务,我们想控制执行方式,应该怎么处理呢?这个时候我们就需要使用Gulp提供的两个非常强大的方法:series() 和parallel()。为什么说强大呢,因为这两个方法可以将多个独立的任务组合成一个更大的操作。

在这里插入图片描述

​ series 和 parallel的用法就是如此,我们还可以,任意自由组合使用这两个方法,例如:

在这里插入图片描述

gulpfile.js的编辑,基本就是上述的过程,接下来我们看看,_Gulp___给我们提供了哪些___API

2.5 Gulp的API

​ 在了解API之前,我们先来了解一些概念:

  • Glob glob就是一个字符串,这个字符串是用来匹配路径的。

    ​ 在glob中可以使用的字符:

    *    /    \\   **   !   
    

    ​ 我们先说一下什么是字符串片段:

    "hello/zero/world"
    

    ​ 上面的字符串中,hellozeroworld,这三个就是字符串片段,就是字符串中用/分隔开的字符串。

    ​ *: 匹配的是 ___单个字符串片段___中的任意字符,例如:

    "src/*.js"
    

    ​ /:是分隔符号,用来表示分隔的。

    \\ :是转义字符的意思,如:"hello_\\*_zero",这里面的\\ 将*转义为字符串"*",那么"*"将只会匹配"*"字符
    

    ​ **:在多个字符串片段中匹配任意数量的字符。例如

    "scripts/**/*.js"
    

    ​ 上述的例子会匹配scripts/index.jsscripts/nested/index.jsscripts/nested/twice/index.js

    !:由于 glob 匹配时是按照每个 glob 在数组中的位置依次进行匹配操作的,所以 glob 数组中的取反(negative)glob 必须跟在一个非取反(non-negative)的 glob 后面。第一个 glob 匹配到一组匹配项,然后后面的取反 glob 删除这些匹配项中的一部分。如果取反 glob 只是由普通字符组成的字符串,则执行效率是最高的。例如:

    ["script/**/*.js", "!script/vendor/"]
    

    ​ 总结:glob就是指上述我们示例中的字符串。

    • Vinyl

      虚拟的文件格式。它是用来描述文件的(包括文件路径,内容等其他数据)。我们对文件的读取和写入都是通过这个东西来完成的。

    • Vinyl 适配器

      Vinyl 适配器就是给我提供了两个方法,分别用于创建读取文件Vinyl描述的流,创建将VInyl写入文件系统的流:

      src(globs, [options]):简单的理解,就是这个方法用于读取文件

      dest(folder, [options]):简单的理解,就是这个方法用于写入文件

    1. src():

      用于创建读取从文件系统中读取Vinyl的流,这个流可以在pipe中流动。换句话说,src返回的流可以读取文件的Vinyl的描述。

      src(globs, [options])
      
    2. dest():

      用于创建一个将Vinyl对象写入文件系统的流。换句话说,dest返回的流可以将Vinyl写入文件系统。

      dest(directory, [options])
      
    3. symlink():

      创建一个流,用于连接VInyl对象和文件系统。也就是说,用这个流可以操作文件系统。

      symlink(directory, [options])
      
    4. lastRun():

      检索在当前运行进程中成功完成任务的最后一次时间。最有用的后续任务运行时,监视程序正在运行。当监视程序正在运行时,对于后续的任务运行最有用。

      当与 src() 组合时,通过跳过自上次成功完成任务以来没有更 改的文件,使增量构建能够加快执行时间。

      lastRun(task, [precision])
      
    5. series():

      将任务函数或操作,组合成更大的任务。组成大任务的小任务,将依次按顺序执行。

      series(...tasks)
      
    6. parallel():

      将任务函数或操作,组合成更大的任务。组成大任务的小任务,将同时执行。

      parallel(...tasks)
      
    7. watch():

      监听globs(匹配到的文件),并在发生更改时运行任务。

      watch(globs, [options], [task])
      
    8. registry():

      允许将自定义的注册表插入到任务系统中,以期提供共享任务或增强功能。

      注意: 只有用 task() 方法注册的任务才会进入自定义注册表中。直接传递给 series()parallel() 的任务函数(task functions)不会进入自定义任务注册表 - 如果你需要自定义注册表的行为,请通过字符串引用的方式将任务(task)组合在一起。

      分配新注册表时,将传输当前注册表中的每个任务,并将用新注册表替换当前注册表。这允许按顺序添加多个自定义注册表。

      registry([registryInstance])
      

      示例一下:

      const { registry, task, series } = require('gulp');
      const FwdRef = require('undertaker-forward-reference');
      
      registry(FwdRef());
      
      task('default', series('forward-ref'));
      
      task('forward-ref', function(cb) {
        // body omitted
        cb();
      });
      
    9. tree():

      获取当前任务依赖树。

      tree([options])
      

      options包含一个属性:deep ,这个属性是boolean类型的数据,默认是false。

      tree({deep: true})
      
    10. Vinyl:

      虚拟的文件格式。就是用来描述文件的,它会包含文件的路径、内容等其他数据。

      new Vinyl([options])
      

      options的属性值如下:

      类型默认值
      stringprocess.cwd
      string
      string
      oryarray
      object
      entsReadableStream、Buffer、null
    11. Vinyl.isVinyl():

      用于检测一个对象是否是Vinyl的示例。

      Vinyl.isVinyl(file);
      
    12. Vinyl.isCustomProp():

      确定一个属性是否由 Vinyl 在内部进行管理。Vinyl 在构造函数中设置值或在 clone() 实例方法中复制属性时使用。

      Vinyl.isCustomProp(property)
      

      参数property的类型是string,是要检查的属性名。

    总结:到目前为止,我们已经把Gulp这个工具的使用过程和方式已经介绍完毕了,大家可以在自己的项目中使用Gulp技术了。

    不同的技术适应不同的场景,我们考虑是否要使用一个技术,则需要看我们的应用场景是什么。不是说,一味地使用更多的技术就是好的。比如webpack、gulp,他们的适用场景就不一样,我们需要打包模块化的包,则可以选择webpack,我们希望控制构建流程则可以选择Gulp,当然我们也可以将webpack和Gulp技术组合使用,前提是看我们的应用场景是什么。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值