Study Notes

本博主会持续更新各种前端的技术,如果各位道友喜欢,可以关注、收藏、点赞下本博主的文章。

Gulp

用自动化构建工具增强你的工作流程!

gulp 将开发流程中让人痛苦或耗时的任务自动化,从而减少你所浪费的时间、创造更大价值。

基本使用

安装 gulp

npm i gulp -D

在项目根目录下创建gulpfile.js文件

function defaultTask(cb) {
// 在此处写默认任务的代码
cb();
} function fooTask(cb) {
// 在此处写自定义任务的代码
cb();
} exports.default = defaultTask;
exports.foo = fooTask;

package.json文件中配置

{
"script": {
"gulp": "gulp"
}
}

测试

在项目根目录下执行 gulp 命令:

默认执行 default 任务

npm run gulp

执行 foo 任务

npm run gulp foo

<span id="createTask"></span>

创建任务

每个 gulp 任务(task)都是一个异步的 JavaScript 函数,此函数是一个可以接收 callback 作为参数的函数,或者是一个返回 stream、promise、event emitter、child process 或 observable (后面会详细讲解) 类型值的函数。由于某些平台的限制而不支持异步任务,因此 gulp 还提供了一个漂亮 替代品。

导出任务

任务(tasks)可以是 public(公开) 或 private(私有) 类型的。

  • 公开任务(Public tasks) 从 gulpfile 中被导出(export),可以通过 gulp 命令直接调用。
  • 私有任务(Private tasks) 被设计为在内部使用,通常作为 series() 或 parallel() 组合的组成部分。

一个私有(private)类型的任务(task)在外观和行为上和其他任务(task)是一样的,但是不能够被用户直接调用。如需将一个任务(task)注册为公开(public)类型的,只需从 gulpfile 中导出(export)即可。

const { series } = require('gulp');

// `clean` 函数并未被导出(export),因此被认为是私有任务(private task)。
// 它仍然可以被用在 `series()` 组合中。
function clean(cb) {
// body omitted
cb();
} // `build` 函数被导出(export)了,因此它是一个公开任务(public task),并且可以被 `gulp` 命令直接调用。
// 它也仍然可以被用在 `series()` 组合中。
function build(cb) {
// body omitted
cb();
} exports.build = build;
exports.default = series(clean, build);

组合任务

Gulp 提供了两个强大的组合方法: series() 和 parallel(),允许将多个独立的任务组合为一个更大的操作。这两个方法都可以接受任意数目的任务(task)函数或已经组合的操作。series() 和 parallel() 可以互相嵌套至任意深度。

如果需要让任务(task)按顺序执行,请使用 series() 方法。

const { series } = require('gulp');

function transpile(cb) {
// body omitted
cb();
} function bundle(cb) {
// body omitted
cb();
} exports.build = series(transpile, bundle);

对于希望以最大并发来运行的任务(tasks),可以使用 parallel() 方法将它们组合起来。

const { parallel } = require('gulp');

function javascript(cb) {
// body omitted
cb();
} function css(cb) {
// body omitted
cb();
} exports.build = parallel(javascript, css);

当 series() 或 parallel() 被调用时,任务(tasks)被立即组合在一起。这就允许在组合中进行改变,而不需要在单个任务(task)中进行条件判断。

const { series } = require('gulp');

function minify(cb) {
// body omitted
cb();
} function transpile(cb) {
// body omitted
cb();
} function livereload(cb) {
// body omitted
cb();
} if (process.env.NODE_ENV === 'production') {
exports.build = series(transpile, minify);
} else {
exports.build = series(transpile, livereload);
}

series() 和 parallel() 可以被嵌套到任意深度。

const { series, parallel } = require('gulp');

function clean(cb) {
// body omitted
cb();
} function cssTranspile(cb) {
// body omitted
cb();
} function cssMinify(cb) {
// body omitted
cb();
} function jsTranspile(cb) {
// body omitted
cb();
} function jsBundle(cb) {
// body omitted
cb();
} function jsMinify(cb) {
// body omitted
cb();
} function publish(cb) {
// body omitted
cb();
} exports.build = series(
clean,
parallel(cssTranspile, series(jsTranspile, jsBundle)),
parallel(cssMinify, jsMinify),
publish,
);

当一个组合操作执行时,这个组合中的每一个任务每次被调用时都会被执行。例如,在两个不同的任务(task)之间调用的 clean 任务(task)将被执行两次,并且将导致不可预期的结果。因此,最好重构组合中的 clean 任务(task)。

如果你有如下代码:

// This is INCORRECT
const { series, parallel } = require('gulp'); const clean = function (cb) {
// body omitted
cb();
}; const css = series(clean, function (cb) {
// body omitted
cb();
}); const javascript = series(clean, function (cb) {
// body omitted
cb();
}); exports.build = parallel(css, javascript);

重构为:

const { series, parallel } = require('gulp');

function clean(cb) {
// body omitted
cb();
} function css(cb) {
// body omitted
cb();
} function javascript(cb) {
// body omitted
cb();
} exports.build = series(clean, parallel(css, javascript));

异步执行

Node 库以多种方式处理异步功能。最常见的模式是 error-first callbacks,但是你还可能会遇到 streamspromisesevent emitterschild processes, 或 observables。gulp 任务(task)规范化了所有这些类型的异步功能。

任务(task)完成通知

当从任务(task)中返回 stream、promise、event emitter、child process 或 observable 时,成功或错误值将通知 gulp 是否继续执行或结束。如果任务(task)出错,gulp 将立即结束执行并显示该错误。

当使用 series() 组合多个任务(task)时,任何一个任务(task)的错误将导致整个任务组合结束,并且不会进一步执行其他任务。当使用 parallel() 组合多个任务(task)时,一个任务的错误将结束整个任务组合的结束,但是其他并行的任务(task)可能会执行完,也可能没有执行完。

返回 stream

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

const streamTask = () => src('src/css/*.css').pipe(dest('dist/css'));

exports.default = streamTask;

返回 promise

const promiseTask = () => Promise.resolve('the value is ignored');

exports.default = promiseTask;

返回 event emitter

const { EventEmitter } = require('events');

const eventEmitterTask = () => {
const emitter = new EventEmitter();
// 发射必须异步发生,否则gulp尚未监听
setTimeout(() => emitter.emit('finish'), 250);
return emitter;
}; exports.default = eventEmitterTask;

返回 child process

const { exec } = require('child_process');

const childProcessTask = () => exec('date');

exports.default = childProcessTask;

返回 observable

const { of } = require('rxjs');

const observableTask = () => of(1, 2, 3);

exports.default = observableTask;

使用 callback

如果任务(task)不返回任何内容,则必须使用 callback 来指示任务已完成。在如下示例中,callback 将作为唯一一个名为 cb() 的参数传递给你的任务(task)。

const callbackTask = (cb) => {
// `cb()` 应该由一些异步工作来调用
cb();
}; exports.default = callbackTask;

如需通过 callback 把任务(task)中的错误告知 gulp,请将 Error 作为 callback 的唯一参数。

const callbackError = (cb) => {
// `cb()` 应该由一些异步工作来调用
cb(new Error('error'));
}; exports.default = callbackError;

然而,你通常会将此 callback 函数传递给另一个 API ,而不是自己调用它。

const fs = require('fs');

const passingCallback = (cb) => {
fs.access('gulpfile.js', cb);
}; exports.default = passingCallback;

gulp 不再支持同步任务(Synchronous tasks)

gulp 不再支持同步任务(Synchronous tasks)了。因为同步任务常常会导致难以调试的细微错误,例如忘记从任务(task)中返回 stream。

当你看到 "Did you forget to signal async completion?" 警告时,说明你并未使用前面提到的返回方式。你需要使用 callback 或返回 stream、promise、event emitter、child process、observable 来解决此问题。

使用 async/await

如果不使用前面提供到几种方式,你还可以将任务(task)定义为一个 async 函数,它将利用 promise 对你的任务(task)进行包装。这将允许你使用 await 处理 promise,并使用其他同步代码。

const fs = require('fs');

const asyncAwaitTask = async () => {
const { version } = JSON.parse(fs.readFileSync('package.json'));
console.log(version, '版本号');
await Promise.resolve('some result');
}; exports.default = asyncAwaitTask;

文件处理

gulp 暴露了 src() 和 dest() 方法用于处理计算机上存放的文件。

src() 接受 glob 参数,并从文件系统中读取文件然后生成一个 Node 流(stream)。它将所有匹配的文件读取到内存中并通过流(stream)进行处理。

由 src() 产生的流(stream)应当从任务(task)中返回并发出异步完成的信号,就如 创建任务(task) 文档中所述。

流(stream)所提供的主要的 API 是 .pipe() 方法,用于连接转换流(Transform streams)或可写流(Writable streams)。

const { src, dest } = require('gulp');
const babel = require('gulp-babel'); const streamJsTask = () =>
src('src/js/*.js').pipe(babel()).pipe(dest('dist/js'));
exports.default = streamJsTask;

dest() 接受一个输出目录作为参数,并且它还会产生一个 Node 流(stream),通常作为终止流(terminator stream)。当它接收到通过管道(pipeline)传输的文件时,它会将文件内容及文件属性写入到指定的目录中。gulp 还提供了 symlink() 方法,其操作方式类似 dest(),但是创建的是链接而不是文件( 详情请参阅 symlink() )。

大多数情况下,利用 .pipe() 方法将插件放置在 src() 和 dest() 之间,并转换流(stream)中的文件。

向流(stream)中添加文件

src() 也可以放在管道(pipeline)的中间,以根据给定的 glob 向流(stream)中添加文件。新加入的文件只对后续的转换可用。如果 glob 匹配的文件与之前的有重复,仍然会再次添加文件。

这对于在添加普通的 JavaScript 文件之前先转换部分文件的场景很有用,添加新的文件后可以对所有文件统一进行压缩并混淆(uglifying)。

const { src, dest } = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify'); const streamAddJsTask = () =>
src('src/js/*.js')
.pipe(babel())
.pipe(src('src/vendor/*.js'))
.pipe(uglify())
.pipe(dest('dist/js')); exports.default = streamAddJsTask;

分阶段输出

dest() 可以用在管道(pipeline)中间用于将文件的中间状态写入文件系统。当接收到一个文件时,当前状态的文件将被写入文件系统,文件路径也将被修改以反映输出文件的新位置,然后该文件继续沿着管道(pipeline)传输。

此功能可用于在同一个管道(pipeline)中创建未压缩(unminified)和已压缩(minified)的文件。

const { src, dest } = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename'); const streamSegmentJsTask = () =>
src('src/js/*.js')
.pipe(babel())
.pipe(src('src/vendor/*.js'))
.pipe(dest('dist/js/'))
.pipe(uglify())
.pipe(rename('index.min.js'))
.pipe(dest('dist/js/')); exports.default = streamSegmentJsTask;

模式:流动(streaming)、缓冲(buffered)和空(empty)模式

src() 可以工作在三种模式下:缓冲(buffering)、流动(streaming)和空(empty)模式。这些模式可以通过对 src() 的 buffer 和 read 参数 进行设置。

缓冲(Buffering)模式是默认模式,将文件内容加载内存中。插件通常运行在缓冲(buffering)模式下,并且许多插件不支持流动(streaming)模式。

流动(Streaming)模式的存在主要用于操作无法放入内存中的大文件,例如巨幅图像或电影。文件内容从文件系统中以小块的方式流式传输,而不是一次性全部加载。如果需要流动(streaming)模式,请查找支持此模式的插件或自己编写。

空(Empty)模式不包含任何内容,仅在处理文件元数据时有用。

使用插件

文件监控

Gulp自动化构建的基本使用的更多相关文章

  1. gulp自动化构建工具的使用

    gulp自动化构建工具: 把前端开发常见的处理(“搬砖”)程序,通过一个工具模块管理起来,只需配置一次,达到自动处理目的,简化开发,提高效率!! 安装: 1.全局安装(全局安装一个gulp命令) A. ...

  2. gulp 自动化构建html项目--自动刷新

    使用gulp自动化构建项目是前端学习的重要部分,gulp依赖于node.js.首选电脑要配置node和npm. 查看node版本号 node --version 查看npm 版本 npm --vers ...

  3. gulp自动化构建工具

    gulp    自动化构建工具,实时监控.代码合并.压缩... http://www.gulpjs.com.cn/     中文网 http://gulpjs.com/plugins/     英文网 ...

  4. gulp自动化构建

    最近正在使用gulp去帮我自动化构建一些技术块,感觉很爽,所以把gulp操作步骤给写笔记,记录下来... 首先了解什么是gulp? 我的理解是一个工具并且自动化的,能帮你把一些前端技术的语法转换成当前 ...

  5. Gulp(自动化构建工具 )

    前言 Gulp,简而言之,就是前端自动化开发工具,利用它,我们可以提高开发效率. 比如: 1.  压缩js 2.  压缩css 3.  压缩less 4.  压缩图片 等等… 我们完全可以利用Gulp ...

  6. gulp自动化构建教程

    gulp及gulpfile.js编写示例    本文主要记录一个gulpfile.js示例,以免以后用的时候遗忘.但首先还是要了解gulp是什么以及如何使用. 一.什么是gulp 简单来说:就是压缩前 ...

  7. gulp自动化构建工具安装使用(1)

    我用的是windows,所以以下操作针对于windows用户,其他系统有不一样的地方请自行查阅资料更正. 好了,废话少说,反正也就是随手捣腾.下雨了,天晴了,我们开始搞gulp了 安装:gulp是个构 ...

  8. gulp自动化构建工具使用总结

    简介: gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器:她不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成:使用她,我们不仅可以很愉快的编写代码 ...

  9. Gulp自动化构建工具的简单使用

    相关网站 gulp官方网址:http://gulpjs.com gulp中文网站:http://www.gulpjs.com.cn/ gulp插件地址:http://gulpjs.com/plugin ...

随机推荐

  1. linux(fedora30):安装/配置maven(maven3.6.1)

    一,maven的用途 1,用途 Maven 是一个项目管理工具,主要用于项目构建,依赖管理,项目信息管理 maven可以用来: 帮用户下载jar包, 有依赖包时自动下载所需的依赖包 打包war包或ja ...

  2. 【Azure微服务 Service Fabric 】在SF节点中开启Performance Monitor及设置抓取进程的方式

    前提条件 当我们观察到SF中某一个节点出现CPU不正常的情况,但是由于不能肉眼长期观察,所以可以通过开启Performance Monitor的方式来获取每一个进程的%Processer Time的方 ...

  3. 因果推理综述——《A Survey on Causal Inference》一文的总结和梳理

    因果推理 本文档是对<A Survey on Causal Inference>一文的总结和梳理. 论文地址 简介 关联与因果 先有的鸡,还是先有的蛋?这里研究的是因果关系,因果关系与普通 ...

  4. Linux的安全模型

    3A 资源分派: Authentication:认证,验证用户身份 Authorization:授权,不同的用户设置不同权限 Accouting|Audition:审计 当用户登录成功时,系统会自动分 ...

  5. Tensorflow学习笔记No.8

    使用VGG16网络进行迁移学习 使用在ImageNet数据上预训练的VGG16网络模型对猫狗数据集进行分类识别. 1.预训练网络 预训练网络是一个保存好的,已经在大型数据集上训练好的卷积神经网络. 如 ...

  6. E. Tree Queries 解析(思維、LCA)

    Codeforce 1328 E. Tree Queries 解析(思維.LCA) 今天我們來看看CF1328E 題目連結 題目 給你一棵樹,並且給你\(m\le2e5\)個詢問(包含\(k\)個點) ...

  7. java数据结构-04单循环链表

    单循环链表与单链表的不同是,单循环链表尾结点的next指向第一个结点(或头结点)  代码: 无头结点: public class SingleCircleLinkedList<E> ext ...

  8. 【算法】二叉树、N叉树先序、中序、后序、BFS、DFS遍历的递归和迭代实现记录(Java版)

    本文总结了刷LeetCode过程中,有关树的遍历的相关代码实现,包括了二叉树.N叉树先序.中序.后序.BFS.DFS遍历的递归和迭代实现.这也是解决树的遍历问题的固定套路. 一.二叉树的先序.中序.后 ...

  9. 01 . Go之Gin+Vue开发一个线上外卖应用

    项目介绍 我们将开始使用Gin框架开发一个api项目,我们起名为:云餐厅.如同饿了么,美团外卖等生活服务类应用一样,云餐厅是一个线上的外卖应用,应用的用户可以在线浏览商家,商品并下单. 该项目分为客户 ...

  10. 【Jmeter】Jmeter安装配置教程

    jmeter安装配置教程 1.安装jdk,配置环境变量 进入官网,https://www.oracle.com/downloads/index.html#java,选择 Java (JDK) for ...