Gulp のプラグインを自分で作ってみます。 gulp のレポジトリにドキュメントがあるのでそれを読むのがいいですが、メモとして書き残しておきます。

用意

プラグインの中で使う gulp-utilthrough2 をインストールしておきます。 gulp は動作確認用です。

$ npm install -g gulp
$ npm install -D gulp-util through2

何もしないプラグイン

簡単な例として「何もしない」をするプラグインを書きます。

// a.js

const through = require('through2');

module.exports = () => through.obj((file, encoding, callback) => {
    callback(null, file);
});

これがプラグインの本体です。

Gulp は vinyl という仮想ファイルを扱うライブラリと、 Node.js の stream を利用してファイルを扱っています。

例では through2obj という関数でオブジェクトを扱う stream を作っています。 file には vinyl のファイルオブジェクトがわたってきます。普通はこれを何かしら変換するのですが、とりあえず何もしていません。次のプラグインにファイルを渡すため callback にそのまま file をわたします。 callback の第一引数はエラーがあったときにはエラーオブジェクトをわたします。

これを使う gulpfile.js が以下です。

// gulpfile.js

const gulp = require('gulp');

const a = require('./a');

gulp.task('default', () =>
    gulp.src(['*.txt'])
        .pipe(a())
        .pipe(gulp.dest('out')));

arequire して pipe を使ってつなげています。

a はなにもしないので、実行すると .txt ファイルが out にそのままコピーされます。

$ echo X > x.txt
$ gulp
$ ls out
x.txt

テキストを JavaScript に変換する

これだけでは意味が無いので、もっと益のあるプラグインを書いてみます。

.txt なファイルを Node.js から require で読み込める .js ファイルに変換するプラグインです。

// a.js

const gutil = require('gulp-util');
const through = require('through2');

module.exports = () => through.obj((file, encoding, callback) => {
    if (file.isNull()) {
        callback(null, file);
        return;
    }

    if (file.isStream()) {
        callback(new gutil.PluginError('a', 'Streams not supported'));
        return;
    }

    if (file.isBuffer()) {
        const text = file.contents.toString('utf8');
        const script = `module.exports = ${JSON.stringify(text)};\n`;
        callback(null, new gutil.File({
            base: file.base,
            cwd: file.cwd,
            path: gutil.replaceExtension(file.path, '.js'),
            contents: new Buffer(script, 'utf8')
        }));
        return;
    }
});

file.isNull() はファイルの中身がないときに true になります。 gulp.src{ read: false } というオプションをわたした時に目にします。ファイル名だけわかればいい場合はこれを使います。

file.isStream() は何かしらのプラグインがファイルの中身を stream にして次にわたしたとき true になります。今回はサポートしないで例外を callback の第一引数にわたします。 gulp-utilPluginError は Gulp プラグインが投げるエラーです。第一引数にプラグインの名前を、第二引数にメッセージをわたします。

file.isBuffer() はファイルの中身が Buffer としてわたってきた場合 true になります。今回はこれを変換して次に渡すことにします。

file.contentsBuffer が入っているので toString('utf8') で文字列にします。 これを JSON.stringify を利用しつつ module.exports = ... の Node.js で使えるモジュールの形にしています。

gulp-utilFile はそのまま vinylFile です。新しいファイルを作って callback にわたします。 base cwd はそのまま、 pathgulp-utilreplaceExtension を使って買う調子を .js に変換しています。 contents にはファイルの中身をわたします。この場合変換後の JavaScript を Buffer にして使っています。

これでテキストを Node.js から使えるモジュールに変換するプラグインができました。先ほどと同じ gulpfile.js を使ってコマンドを実行すると期待した変更をします。

$ gulp
$ ls out
x.js
$ cat out/x.js
module.exports = "X\n"

さいごに

through2 を使って簡単なプラグインを作りました。Gulp は stream や vinyl というしくみに乗っかっているので npm モジュールも活用しやすいです。

広く便利なものができればテストなんかも書いて npm に公開するのもいいと思います。プロジェクト固有のプラグインも相対パスで require するだけなので気軽に作ることができます。