之前挖了个坑,准备写篇gulp插件编写入门的科普文,之后迟迟没有动笔,因为不知道该肿么讲清楚Stream这货,毕竟,gulp插件的实现不像grunt插件的实现那么直观。

好吧,于是决定单刀直入了。文中插件示例可在这里找到:https://github.com/chyingp/gulp-preprocess

写在前面

我们来看看下面的gruntfile,里面用到了笔者刚写的一个gulp插件gulp-preprocess。好吧,npm publish的时候才发现几个月前就被抢注了。为什么星期天晚上在 http://npmjs.org/package/ 上没有搜到 TAT

这个插件基于preprocess这个插件,插件使用方法请自行脑补。本文就讲解下如何实现 gulp-preprocess 这个插件

var gulp = require('gulp'),
preprocess = require('gulp-preprocess'); gulp.task('default', function() {
gulp.src('src/index.html')
.pipe(preprocess({USERNAME:'程序猿小卡'}))
.pipe(gulp.dest('dest/'));
});

进入实战

关键代码

我们来看下最关键的几行代码。可以看到,上文的 preprocess() 的作用就是返回一个定制的 Object Stream ,这是实现gulp的流式操作必需的,其他gulp插件也大同小异。

gulp-preprocess/index.js

module.exports = function (options) {
return through.obj(function (file, enc, cb) {
// 主体实现忽略若干行
});
};

接着,看下具体实现。实际上代码很短

引入依赖

首先,引入插件的依赖项。其中:

  • gutil:按照gulp的统一规范打印错误日志
  • through2:Node Stream的简单封装,目的是让链式流操作更加简单
  • preprocess:文本预处理器,主要就是文本替换啦
'use strict';
var gutil = require('gulp-util');
var through = require('through2');
var pp = require('preprocess');

核心逻辑

其次,定义gulp-preprocess的主体代码。没错,就是下面这么短的代码。代码结构也比较清晰,下面还是简单做下分解介绍。

module.exports = function (options) {
return through.obj(function (file, enc, cb) {
if (file.isNull()) {
this.push(file);
return cb();
} if (file.isStream()) {
this.emit('error', new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
return cb();
} var content = pp.preprocess(file.contents.toString(), options || {});
file.contents = new Buffer(content); this.push(file); cb();
});
};

核心代码分解

还是直接上代码,在关键位置加上注释。对 through2 不熟悉的童鞋可以参考这里

module.exports = function (options) {
return through.obj(function (file, enc, cb) { // 如果文件为空,不做任何操作,转入下一个操作,即下一个 .pipe()
if (file.isNull()) {
this.push(file);
return cb();
} // 插件不支持对 Stream 对直接操作,跑出异常
if (file.isStream()) {
this.emit('error', new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
return cb();
} // 将文件内容转成字符串,并调用 preprocess 组件进行预处理
// 然后将处理后的字符串,再转成Buffer形式
var content = pp.preprocess(file.contents.toString(), options || {});
file.contents = new Buffer(content); // 下面这两句基本是标配啦,可以参考下 through2 的API
this.push(file); cb();
});
};

写在后面

要把gulp插件内部实现的原理讲透不是件容易的事情,因为实现还是比较复杂的,首先需要对Buffer、Stream 有一定的了解,包括如何通过Node暴露的API对Stream进行定制化。可以参考笔者的另一篇随笔《gulp.src()内部实现探究》,虽然也只是讲了很小的一部分。

Gulp:插件编写入门的更多相关文章

  1. 如何编写一个gulp插件

    很久以前,我们在"细说gulp"随笔中,以压缩JavaScript为例,详细地讲解了如何利用gulp来完成前端自动化. 再来短暂回顾下,当时除了借助gulp之外,我们还利用了第三方 ...

  2. chrome插件编写基本入门

    chrome插件编写基本入门  http://igeekbar.com/igeekbar/post/331.htm #精选JAVASCRIPTCHROME 作为一名程序猿,怎么能不会写chrome插件 ...

  3. Gulp资料大全:入门、插件、脚手架、包清单

    awesome-gulp中文版 一份gulp的资源,插件和使用实例清单, 致力于打造更好的前端工程构建流程. 被老外的awesome 清单刺激到,觉得有必要翻译一份,为国产的程序员们做点事情,本清单将 ...

  4. gulp 插件

    原文链接:http://www.mamicode.com/info-detail-517085.html gulp是什么? http://gulpjs.com/ 相信你会明白的! 与著名的构建工具gr ...

  5. 将less编译成css的gulp插件

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

  6. 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)

    前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...

  7. jQuery插件编写及链式编程模型小结

    JQuery极大的提高了我们编写JavaScript的效率,让我们可以愉快的编写代码,做出各种特效.大多数情况下,我们都是使用别人开发的JQuery插件,今天我们就来看看如何把我们常用的功能做出JQu ...

  8. gulp.js基础入门

    安装 Node 去 nodejs.org 根据系统选择性按照教程安装Node. 创建项目 创建项目文件夹 进入项目文件夹 初始化项目 使用npm命令:npm init,根据提示完成. 安装 Gulp ...

  9. gulp插件(gulp-jmbuild),用于WEB前端构建

    源码地址:https://github.com/jiamao/gulp-jmbuild https://github.com/jiamao/gulp-jmbuild gulp-jmbuild gulp ...

随机推荐

  1. python基础知识回顾之元组

    元组与列表的方法基本一样,只不过创建元组是用小括号()把元素括起来,两者的区别在于,元组的元素不可被修改. 元组被称为只读列表,即数据可以被查询,但不能被修改,列表的切片操作适用于元组. 元组写在小括 ...

  2. Spring中的destroy-method方法

    1. Bean标签的destroy-method方法 配置数据源的时候,会有一个destroy-method方法 <bean id = "dataSource" class  ...

  3. Springboot系列:Springboot与Thymeleaf模板引擎整合基础教程(附源码)

    前言 由于在开发My Blog项目时使用了大量的技术整合,针对于部分框架的使用和整合的流程没有做详细的介绍和记录,导致有些朋友用起来有些吃力,因此打算在接下来的时间里做一些基础整合的介绍,当然,可能也 ...

  4. MFC 常用功能总结

    目录 ◆ 获取启动参数◆ 调整窗体大小◆ 关闭Dialog窗体◆ Dialog启动时指定控件为焦点◆ Dialog中禁止ESC回车关闭窗体◆ 回车后焦点自动跳到下一个控件◆ 窗体中某个控件捕获右键菜单 ...

  5. MongoDB之 复制集搭建

    MongoDB复制集搭建步骤,本次搭建使用3台机器,一个是主节点,一个是从节点,一个是仲裁者. 主节点负责与前台客户端进行数据读写交互,从节点只负责容灾,构建高可用,冗余备份.仲裁者的作用是当主节点宕 ...

  6. 第 14 章 结构和其他数据形式(enum枚举)

    /*----------------------------- enum.c -- 使用枚举类型的值 -----------------------------*/ #include <stdi ...

  7. gdb调试:

    1 简介      GDB(GNU Debugger)是GCC的调试工具.其功能强大,现描述如下:      GDB主要帮忙你完成下面四个方面的功能:      1.启动你的程序,可以按照你的自定义的 ...

  8. 2019 wannafly winter camp

    2019 wannafly winter camp Name Rank Solved A B C D E F G H I J K day1 9 5/11 O O O O O day2 5 3/11 O ...

  9. 记录使用git submodule时踩的坑

    在使用git子模块的时候踩了一个坑 在使用git submodule updata --init --recursive命令,即递归更新子模块并初始化时碰到了一个问题: 经过一段不短时间的排查,发现问 ...

  10. 小程序push数组,渲染不出来解决办法

    1.在data中,定义一个空数组: zhou_time:[] 2.声明: var zhou_time = this.data.zhou_time; 3.PUSH赋值: zhou_time.push({ ...