gulp3のrun-sequence + エラー処理なコードを、gulp4で置き換える

いろいろ

gulp3にタスクを連続で実行するrun-sequenceというライブラリがありました。

gulpのバージョン4以降では、このrun-sequenceの代わりに、gulp.seriesを使うことになったのだが、 gulp.seriesには、run-sequenceにあった、発生したエラーを受け取るcallbackが用意されていませんでした。

try-catch文を使っても、gulp.series内で発生したエラーを拾うことはできない。
では、gulp3 → gulp4と書き換える際、run-sequenceをどのように書き換えるべきか。


gulp3 + run-sequenceのコード

run-sequenceでは、こんな感じで発生したエラーを拾えていた。

const gulp = require('gulp');
const runSequence = require('run-sequence');

gulp.task('package', (cb) => {
  runSequence('tsc-debug', '_rm-package', '_package-debug', (err) => {
    if (err) {
      gulp.start('_notifyError');
    }
    cb(err);
  });
});


gulp4 + gulp.seriesのコード

エラーを拾うコールバックがgulp.seriesに用意されていないので、
すんなりgulp4に書き換えられない。 エラー処理が抜けてしまう。

const gulp = require('gulp');

gulp.task('package',
  gulp.series('tsc-debug', '_rm-package', '_package-debug'));


gulp.seriesのコードを追ってみる

gulpの各タスクの処理はtaskWrapperで包まれる。
// node_modules/undertaker/lib/set-task.js
function taskWrapper() {
  return fn.apply(this, arguments);
}
gulp.seriesを作成時、createExtensionsが呼ばれる。
// node_modules/undertaker/lib/series.js
function series() {
  var create = this._settle ? bach.settleSeries : bach.series;
  var args = normalizeArgs(this._registry, arguments);
  var extensions = createExtensions(this); // ←←←←←←←←←←←←←←←←←←←
  var fn = create(args, extensions);
createExtensionsで、エラー処理のハンドリングが実装されている
  • エラー発生時にerrorイベントが発行される
// node_modules/undertaker/lib/helpers/createExtensions.js
function createExtensions(ee) {
  return {
    error: function(error, storage) {
      if (Array.isArray(error)) {
        error = error[0];
      }
      storage.release();
      ee.emit('error', { // ←←←←←←←←←←←←←←←←←←←
        uid: storage.uid,
        name: storage.name,
        branch: storage.branch,
        error: error,
        duration: process.hrtime(storage.startHr),
        time: Date.now(),
      });
    },
最終的にgulpでエラーを拾える
  • つまり、gulp.series内で発生したエラーは、次のようなコードで拾える。
    • gulp.on('error', エラー処理)
const gulp = require('gulp');

gulp.on('error', (err) => { // ←←←←←←←←←←←←←←←←←←←
  console.log('--- catch error');
});


gulp.seriesで発生したエラーを拾うコードの例(全体)

const gulp = require('gulp');

gulp.task('hello', (cb) => {
  console.log('hello');
  return cb();
});

gulp.task('world', (cb) => {
  console.log('world');
  return cb();
});

gulp.task('gulp', (cb) => {
  console.log('gulp');
  throw new Error('error from task "gulp"');
});

gulp.on('error', (err) => {
  console.log('--- catch error');
});

gulp.task('run', gulp.series('hello', 'world', 'gulp'));


npmのモジュールにしてみた

  • gulp3 run-sequenceの処理を、なるべくそのままgulp4.seriesに置き換えれるようにするnpmモジュール
npm install --save-dev gulp-task-error-handler


gulp3 run-sequenceのコードを、gulp4 gulp.seriesで置き換える例
  • gulp3 run-sequence code
    • 例えば、このようなコードがあったとして、
const gulp = require('gulp');
const runSequence = require('run-sequence');

gulp.task('package', (cb) => {
  runSequence('tsc-debug', '_rm-package', '_package-debug', (err) => {
    if (err) {
      gulp.start('_notifyError');
    }
    cb(err);
  });
});
  • replace with gulp-task-error-handler sample.
    • このモジュールを使うと、このように置き換えられる。
const gulp = require('gulp');
const handleError = require('gulp-task-error-handler');

gulp.task('package',
  handleError(gulp.series('tsc-debug', '_rm-package', '_package-debug'), (err) => {
    gulp.task('_notifyError')();
  })
);


おわり

おわりなのだ。