gulpの「Writing a Plugin - Guidline」日本語版


gulpプラグインの開発者向けドキュメントの中で、MUST Readとなっているガイドラインを日本語に翻訳しました。オリジナルの文書はこちら[Guidelines](https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/guidelines.md)です。

権利者の許可を得て翻訳＆公開します。オリジナルと同じライセンスCC0です。また、末尾に翻訳の更新記録を掲載してあります。誤訳などあればコメント欄で指摘してください。よろしくお願いします。

[![CC0](http://i.creativecommons.org/p/zero/1.0/88x31.png)](http://creativecommons.org/publicdomain/zero/1.0/)

# ガイドライン

> このガイドラインは強制ではありませんが、全てのプラグイン開発者が従うよう **強く** 奨励します。質の悪いプラグインなど誰も使いたくないでしょう。またこのガイドラインは開発者がgulpと相性のいいプラグインを書く手助けになるはずです。

[Writing a Plugin](https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/README.md) > ガイドライン

1. 既存のnodeモジュールを使って容易に出来ることをプラグイン化すべきでない
 - ラッピングできるからといって全部ラッピングしてしまうと、エコシステムに無意味で低品質なプラグインが溢れてしまう
1. プラグインの機能を **一つだけ** にしぼり、かつそれを上手くこなすようにすべき
 - 設定を切り替えて全く関係ない機能を実行してはいけない
1. 他のプラグインに任せられることは実装すべきでない
 - cat（ファイルの結合）をしたければ [gulp-concat](https://github.com/wearefractal/gulp-concat) に任せるべき
 - ファイルにヘッダーを付加したければ [gulp-header](https://github.com/godaddy/gulp-header) に任せるべき
 - ファイルにフッターを付加したければ [gulp-footer](https://github.com/godaddy/gulp-footer) に任せるべき
 - 他のプラグインの機能が必要だが必須でない場合は、他のプラグインと合わせて使うケースがある旨ドキュメントで示すこと
 - 他のプラグインの機能が内部的に必須の場合は、プラグイン内部から他のプラグインを呼び出してpipeでつなげて使うこと
1. プラグインは **必ずテストすること**
 - プラグインのテストは簡単（テストするのにgulpは必要ない）
 - 他のプラグインのテストを参考にすること
1. プラグインの検索にヒットさせるため、`package.json`のキーワード欄に`gulpplugin`を入れること
1. streamの内部で例外を投げないこと
 - 例外のかわりに **error** イベントを発生させるべき
 - stream外部の異常系（例：プラグインのオプションに不正な値が指定された場合など）は、例外を投げてもよい
1. エラーメッセージの先頭にはプラグインの名前を付けること
 - 例：`gulp-replace: streamに対して正規表現による置換はできません`
 - gulp-utilの [PluginError](https://github.com/gulpjs/gulp-util#new-pluginerrorpluginname-message-options) クラスを使うとエラーメッセージを簡単に書ける
1. 入力時の`file.contents`タイプ（null / stream / buffer）を出力時に変更すべきでない
 - file.contentsがnull（入力なし）の場合、プラグインはそれを無視して次の処理にそのまま渡すこと
 - file.contentsがstreamの場合、かつプラグインがstream未対応の場合は、'error'イベントを発生させること
     - 問題を引き起こす可能性があるため、streamをプラグイン内部でバッファリングしてはいけない
1. プラグイン内の処理が終わるまで、`file`オブジェクトを次の処理に渡してはいけない
1. [おすすめのモジュール](https://github.com/gulpjs/gulp/blob/master/docs/writing-a-plugin/recommended-modules.md)を活用すること
1. `gulp`をpackage.jsonのdependencyまたはpeerDependencyに書いてはいけない
 - そうすることに意味は無いし、逆に問題を引き起こすかもしれない

## なぜこのガイドラインは厳格なのか？

gulpはユーザーの理解しやすさを目標としています。厳格なガイドラインを提供することで、一貫性があり高品質なエコシステムを全ての人に提供することができるのです。そのためにプラグイン開発者のやるべきことと考えるべきことが増えるとしても、問題の発生を未然に防ぐことになるでしょう。

## ガイドラインに従わない場合どうなるのか？

npmは全ての人に開かれており、あなたは望むのを自由につくることができます。それでもこのようなガイドラインを規定したのには意味があります。まもなくプラグインの受け入れテストを導入する予定です。それはプラグイン検索機能に組み込まれる予定であり、仮にあなたがこのガイドラインに従わないならば、その旨が検索結果に表示され、検索順位にも反映されるでしょう。ユーザーは "gulpのやり方" に従うプラグインを好むはずです。

## 良いプラグインの例

```js
// through2はnodeのtransform streamをラップするもの
var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;

// 定数
const PLUGIN_NAME = 'gulp-prefixer';

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

// プラグイン関数
function gulpPrefixer(prefixText) {

  if (!prefixText) {
    throw PluginError(PLUGIN_NAME, "Missing prefix text!");
  }
  prefixText = new Buffer(prefixText); // prefixTextを含むBufferオブジェクトは先に生成しておく

  // 入力ファイルを受け取って処理するstreamオブジェクトを生成
  var stream = through.obj(function (file, enc, callback) {
    if (file.isNull()) {
      this.push(file); // 入力なしの場合は何もしない
      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();
    }
  });

  // 生成したstreamオブジェクトを返す
  return stream;
};

// プラグイン関数をエクスポート
module.exports = gulpPrefixer;
```

# （翻訳の更新記録）
- 2014/2/9: 一般公開（2014/2/9時点の原文を翻訳）
- 2014/2/10: 8.を自然な日本語に修正
- 2014/2/13: リストのインデントが間違っていたのを修正
- 2014/3/1: 10.にオリジナル版の変更を反映