跳到主要内容

指南

虽然这些指南完全是可选的,但我们强烈建议每个人都遵循它们。没有人想使用一个糟糕的插件。这些指南实际上会让你的生活更轻松,因为它们能确保你的插件很好地融入 gulp 生态系统。

编写插件 > 指南

  1. 你的插件不应该做那些可以用现有 node 模块轻松完成的事情
    • 例如:删除文件夹不需要是一个 gulp 插件。可以在任务中使用像 del 这样的模块。
    • 为了包装而包装每一个可能的东西会使生态系统充斥着在 gulp 范式中没有意义的低质量插件。
    • gulp 插件是用于基于文件的操作!如果你发现自己在强行将复杂的处理过程塞进流中,那就直接制作一个普通的 node 模块。
    • gulp 插件的一个好例子是像 gulp-coffee 这样的插件。coffee-script 模块本身不支持 Vinyl,所以我们对其进行包装以添加此功能,并抽象出痛点,使其在 gulp 中运行良好。
  2. 你的插件应该只做一件事,并且做好它。
    • 避免那些使你的插件执行完全不同任务的配置选项
    • 例如:JS 压缩插件不应该有一个添加页眉的选项
  3. 你的插件不应该做其他插件负责的事情
    • 它不应该合并文件,gulp-concat 做那个
    • 它不应该添加页眉,gulp-header 做那个
    • 它不应该添加页脚,gulp-footer 做那个
    • 如果是常见但可选的用例,请记录你的插件经常与另一个插件一起使用
    • 在你的插件中使用其他插件!这减少了你需要编写的代码量,并确保生态系统的稳定。
  4. 你的插件必须经过测试
    • 测试 gulp 插件很简单,你甚至不需要 gulp 来测试它
    • 查看其他插件作为示例
  5. 在你的 package.json 中添加 gulpplugin 作为关键词,这样你就会出现在我们的搜索中
  6. 你的插件 API 应该是一个返回流的函数
    • 如果你需要在某处存储状态,请在内部进行
    • 如果你需要在插件之间传递状态/选项,请将其附加到文件对象上
  7. 不要在流内抛出错误
    • 相反,你应该将其作为错误事件发出。
    • 如果你在流外部遇到错误,例如在创建流时遇到无效配置,你可以抛出它。
  8. 用插件名称为任何错误添加前缀
    • 例如:gulp-replace: Cannot do regexp replace on a stream
    • 使用 PluginError 模块可以轻松实现这一点
  9. 适当地命名你的插件:如果它是一个 gulp 插件,它应该以 "gulp-" 开头
    • 如果它不是 gulp 插件,则不应以 "gulp-" 开头
  10. file.contents 的类型在输出时应该始终与输入时相同
    • 如果 file.contents 为 null(non-read),只需忽略该文件并将其传递下去
    • 如果 file.contents 是一个 Stream 并且你不支持它,只需发出一个错误
      • 不要缓冲流以强行使你的插件处理流。这会导致可怕的事情发生。
  11. 在你完成处理文件对象之前,不要将其传递到下游
  12. 克隆文件或基于文件创建新文件时,使用 file.clone()
  13. 使用我们推荐模块页面中的模块来简化你的工作
  14. 不要在你的插件中将 gulp 作为依赖项或 peerDependency
    • 使用 gulp 来测试或自动化你的插件工作流程是完全可以的,只要确保你将其作为 devDependency
    • 将 gulp 作为你的插件的依赖项意味着安装你的插件的任何人也在安装一个新的 gulp 及其整个依赖树。
    • 你不应该在实际的插件代码中使用 gulp。如果你发现自己这样做,请开一个 issue,这样我们可以帮助你。

为什么这些指南如此严格?

gulp 的目标是对用户简单。通过提供严格的指南,我们能够为所有人提供一致和高质量的生态系统。虽然这确实为插件作者增加了一些工作和思考,但它消除了后期的许多问题。

如果我不遵循它们会怎样?

npm 对所有人开放,你可以自由创建任何你想要的东西,但这些指南是有原因的。很快就会有接受测试被整合到插件搜索中。如果你未能遵守插件指南,这将通过评分系统公开可见/可排序。人们总是更喜欢使用符合"gulp 方式"的插件。

一个好的插件是什么样子的?

// through2 是 node transform streams 的一个轻量包装器
var through = require('through2');
var PluginError = require('plugin-error');

// 常量
const PLUGIN_NAME = 'gulp-prefixer';

function prefixStream(prefixText) {
var stream = through();
stream.write(prefixText);
return stream;
}

// 插件级函数(处理文件)
function gulpPrefixer(prefixText) {

if (!prefixText) {
throw new PluginError(PLUGIN_NAME, 'Missing prefix text!');
}
prefixText = new Buffer(prefixText); // 提前分配

// 创建一个每个文件都会通过的流
return through.obj(function(file, enc, cb) {
if (file.isNull()) {
// 返回空文件
return cb(null, file);
}
if (file.isBuffer()) {
file.contents = Buffer.concat([prefixText, file.contents]);
}
if (file.isStream()) {
file.contents = file.contents.pipe(prefixStream(prefixText));
}

cb(null, file);

});

}

// 导出插件主函数
module.exports = gulpPrefixer;