# Guidelines

> While these guidelines are totally optional, we **HIGHLY** recommend that everyone follows them. Nobody wants to use a bad plugin. These guidelines will actually help make your life easier by giving you assurance that your plugin fits well within gulp.

[Writing a Plugin](README.md) > Guidelines

1. Your plugin should not do something that can be done easily with an existing node module
  - Wrapping every possible thing just for the sake of wrapping it will pollute the ecosystem with low quality plugins that don't make sense
1. Your plugin should only do **one thing**, and do it well.
  - Avoid config options that make your plugin do completely different tasks
1. Your plugin shouldn't do things that other plugins are responsible for
  - It should not concat, [gulp-concat](https://github.com/wearefractal/gulp-concat) does that
  - It should not add headers, [gulp-header](https://github.com/godaddy/gulp-header) does that
  - It should not add footers, [gulp-footer](https://github.com/godaddy/gulp-footer) does that
  - If it's a common but optional use case, document that your plugin is often used with another plugin
  - If it's an internal requirement, make use of existing plugins by piping your plugin's output to them
1. Your plugin **must be tested**
  - Testing a gulp plugin is easy, you don't even need gulp to test it
  - Look at other plugins for examples
1. Add `gulpplugin` as a keyword in your `package.json` so you show up on our search
1. Do not throw errors inside a stream
  - Instead, you should emit it as an **error** event.
  - If you encounter an error **outside** the stream, such as invalid configuration, you may throw it.
1. Prefix any errors with the name of your plugin
  - For example: `gulp-replace: Cannot do regexp replace on a stream`
  - Use gulp-util's [PluginError](https://github.com/gulpjs/gulp-util#new-pluginerrorpluginname-message-options) class to make this easy
1. The type of `file.contents` should always be the same going out as it was when it came in
  - If file.contents is null (non-read) just ignore the file and pass it along
  - If file.contents is a Stream and you don't support that just emit an error
  - If you choose to support file.contents as a Stream, use [BufferStream](https://github.com/nfroidure/BufferStream) to make this easy
1. Do not pass the `file` object downstream until you are done with it
1. Make use of the [gulp-util](https://github.com/gulpjs/gulp-util) library
  - It provides templating, CLI colors, logging, changing file extensions
  - Try looking for common things there first and add it if it doesn't exist
1. Do NOT require `gulp` as a dependency or peerDependency
  - There is no reason you should have to do this and it will cause problems if you do

## Why are these guidelines so strict?

gulp aims to be simple for users. By providing strict guidelines we are able to provide a consistent and high-quality ecosystem for everyone. While this does add a little more work and thought for plugin authors, it removes a lot of problems later down the road.

### What happens if I don't follow them?

npm is open for everyone, and you are free to make whatever you want but these guidelines were prescribed for a reason. There are acceptances tests coming soon that will be integrated into the plugin search. If you fail to adhere to the plugin guidelines it will be publicly visible/sortable via a scoring system. People will always prefer to use plugins that match "the gulp way".

### What does a good plugin look like?

```js
// through2 is a thin wrapper around node transform streams
var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;

// Consts
const PLUGIN_NAME = 'gulp-prefixer';

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

// Plugin level function (dealing with files)
function gulpPrefixer(prefixText) {

  if (!prefixText) {
    throw PluginError(PLUGIN_NAME, "Missing prefix text!");
  }
  prefixText = new Buffer(prefixText); // allocate ahead of time

  // Creating a stream through which each file will pass
  var stream = through.obj(function (file, enc, callback) {
    if (file.isNull()) {
      this.push(file); // Do nothing if no contents
      return callback();
    }

    if (file.isBuffer()) {
      file.contents = Buffer.concat([prefixText, file.contents]);
      this.push(file);
      return callback();
    }

    if (file.isStream()) {
      file.contents = file.contents.pipe(prefixStream(prefixText));
      this.push(file);
      return callback();
    }
  });

  // returning the file stream
  return stream;
};

// Exporting the plugin main function
module.exports = gulpPrefixer;
```
