エラーがgulpウォッチを壊す/クラッシュさせるのを防ぎます


178

gulp 3.6.2を実行していて、オンラインのサンプルから設定された次のタスクがあります

gulp.task('watch', ['default'], function () {
  gulp.watch([
    'views/**/*.html',        
    'public/**/*.js',
    'public/**/*.css'        
  ], function (event) {
    return gulp.src(event.path)
      .pipe(refresh(lrserver));
  });

  gulp.watch(['./app/**/*.coffee'],['scripts']);
  gulp.watch('./app/**/*.scss',['scss']);
});

CoffeeScriptのgulpウォッチでエラーが発生したときはいつでも停止します。

他の場所で推奨されているように、私はこれを試しました

gulp.watch(['./app/**/*.coffee'],['scripts']).on('error', swallowError);
gulp.watch('./app/**/*.scss',['scss']).on('error', swallowError);
function swallowError (error) { error.end(); }

しかし、それは機能していないようです。

何が悪いのですか?


@Aperçuの回答に応じて、私は自分のswallowError方法を変更し、代わりに次のことを試しました:

gulp.task('scripts', function () {
  gulp.src('./app/script/*.coffee')
    .pipe(coffee({ bare: true }))
    .pipe(gulp.dest('./public/js'))
    .on('error', swallowError);
});

再起動し、コーヒーファイルに構文エラーを作成しました。同じ問題:

[gulp] Finished 'scripts' after 306 μs

stream.js:94
      throw er; // Unhandled stream error in pipe.
            ^
Error: W:\bariokart\app\script\trishell.coffee:5:1: error: unexpected *
*
^
  at Stream.modifyFile (W:\bariokart\node_modules\gulp-coffee\index.js:37:33)
  at Stream.stream.write (W:\bariokart\node_modules\gulp-coffee\node_modules\event-stream\node_modules\through\index.js:26:11)
  at Stream.ondata (stream.js:51:26)
  at Stream.EventEmitter.emit (events.js:95:17)
  at queueData (W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:43:21)
  at next (W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:71:7)
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:85:7
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\lib\src\bufferFile.js:8:5
  at fs.js:266:14
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\graceful-fs\graceful-fs.js:104:5
  at Object.oncomplete (fs.js:107:15)

3
github.com/gulpjs/gulp/tree/master/docs/recipesにある公式のgulpレシピを参照してください。stream -combiner2を使用してエラーを組み合わせます...これは公式の回答です。
danday74

回答:


257

あなたのswallowError関数は次のようになります。

function swallowError (error) {

  // If you want details of the error in the console
  console.log(error.toString())

  this.emit('end')
}

errorタスクではなく、落ちていたタスクのイベントにこの関数をバインドする必要があると思います。watch問題が発生する場所ではないため、失敗した可能性のあるタスクごとにこのエラーコールバックを設定する必要があります。停止;するwatchタスクを防ぐために、何かを逃した

例:

gulp.task('all', function () {
  gulp.src('./app/script/*.coffee')
    .pipe(coffee({ bare: true }))
    .on('error', swallowError)
    .pipe(gulp.dest('./public/js'))

  gulp.src('css/*.scss')
    .pipe(sass({ compass: true }))
    .on('error', swallowError)
    .pipe(cssmin())
    .pipe(gulp.dest('dist'))
})

別の方法として、別のモジュールを含めても構わない場合は、gulp-utilの log関数を使用して、追加の関数を宣言しないようにすることができます。gulpfile

.on('error', gutil.log)

しかし、イベントのハンドラーを削除するために使用される素晴らしいgulp-plumberプラグインを見て、ストリームの中断を引き起こすことをお勧めします。使い方は非常に簡単で、失敗する可能性のあるすべてのタスクをキャッチできなくなります。onerrorerror

gulp.src('./app/script/*.coffee')
  .pipe(plumber())
  .pipe(coffee({ bare: true }))
  .pipe(gulp.dest('./public/js'))

関連するプラグインの作成者によるこの記事のこれに関する詳細情報。


私はあなたの助けに感謝します。私の編集を参照してください。私はあなたが言っていることをやっていると思うが、それでもうまくいかない
ジョージ・マウアー

2
最終的に正しいことを反映するように回答を編集して、将来これを見つけた人がコメントチェーンを読む必要がないようにすることができます。
George Mauer、2014年

1
これはすべてうまくいっていますが、なぜ独自のエラーハンドラを記述する必要があるのでしょうか。私がgulpやgruntなどの前処理ツールを使用する理由は、それが汚い作業をしてくれるからです。コード内のどこかで構文エラー(発生する可能性があります)が発生しても、システム全体が停止することはありません。これをPrepros(別のプリプロセッサ)のGUIと比較してください。このツールは、エラーがどこにあるのかを正確に通知し、問題が発生してもハングしたり終了したりしません。
Kokodoko

1
公式のgulpレシピですが、steam-combiner2について誰も言及していません。配管工も良いですが、私はいつもgulpのレシピに従うことを好みます。gulpのレシピはgulp
gulpjs /

1
同じ難問に直面して、私は時計機能の結果にgulp.watch()を追加するラッパーを使用することにしました。それは、.on('error', function() { this.emit('end') })ハングアップに対して回復力を持たせたい時計タスクだからです。非常にうまく機能し、失敗した個々のタスクでも独自のエラーメッセージが出力されます。コードを参照してください:github.com/specious/specious.github.io/commit/f8571d28
tknomad

20

上記の例ではうまくいきませんでした。ただし、次のことを行いました。

var plumber = require('gulp-plumber');
var liveReload = require('gulp-livereload');
var gutil = require('gulp-util');
var plumber = require('gulp-plumber');
var compass = require('gulp-compass');
var rename = require('gulp-rename');
var minifycss = require('gulp-minify-css');
var notify = require('gulp-notify');

gulp.task('styles', function () {
    //only process main.scss which imports all other required styles - including vendor files.
    return gulp.src('./assets/scss/main.scss')
            .pipe(plumber(function (error) {
                gutil.log(error.message);
                this.emit('end');
            }))
            .pipe(compass({
                config_file: './config.rb',
                css: './css'
                , sass: './assets/scss'
            }))
            //minify files
            .pipe(rename({suffix: '.min'}))
            .pipe(minifycss())

            //output
            .pipe(gulp.dest('./css'))
            .pipe(notify({message: 'Styles task complete'}));
});

gulp.task('watch', function () {
    liveReload.listen();
    gulp.watch('assets/scss/**/*.scss', ['styles']);
});

これはすばらしいことですが、エラーが発生した場合に通知することもできます(現在、これはターミナルにエラーを記録するだけです)
raison

4

1つの形式のファイル

(例:* .coffeeのみ)

ファイルの1つの形式のみで作業する場合gulp-plumberは、それが解決策です。

たとえば、リッチスクリプトはコーヒースクリプトのエラーと警告を処理しました:

gulp.task('scripts', function() {
  return gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError)
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

複数の種類のファイル形式

(例:* .coffeeと* .jsを同時に)

ただし、複数の種類のファイル形式(例:*.jsおよび*.coffee)を使用しない場合は、私の解決策を掲載します。

私はここに自己説明コードを投稿します。

gulp.task('scripts', function() {
  // plumber don't fetch errors inside gulpif(.., coffee(...)) while in watch process
  return gulp.src(['assets/scripts/**/*.js', 'assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(gulpif(/[.]coffee$/, coffeelint()))
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(gulpif(/[.]coffee$/, coffee({ // if some error occurs on this step, plumber won't catch it
      bare: true
    })))
    .on('error', swallowError)
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

私は問題に直面gulp-plumberしてgulp-if使用してgulp.watch(...

ここで関連する問題を参照してください:https : //github.com/floatdrop/gulp-plumber/issues/23

だから私にとって最良の選択肢は:

  • 各パーツをファイルとして、後に連結します。(うなり声のように)各パーツを個別のファイルで処理できる複数のタスクを作成し、それらを連結します
  • 各パーツをストリームとして、ストリームをマージします。を使用しmerge-streamて作成された2つのストリームを1つにマージしevent-stream、ジョブを続行します(私は最初にそれを試しましたが、それは私にとってはうまくいくので、以前のものよりも高速です)

各パーツをストリームとして、その後ストリームをマージ

彼女は私のコードの主要部分です:

gulp.task('scripts', function() {
  coffeed = gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError);

  jsfiles = gulp.src(['assets/scripts/**/*.js']);

  return merge([jsfiles, coffeed])
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

各パーツをファイルとして、後に連結

これをパーツに分割する場合、各パーツに結果ファイルが作成されるはずです。例:

gulp.task('scripts-coffee', function() {

  return gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError)
    .pipe(concat('application-coffee.js'))
    .pipe(gulp.dest('dist/scripts'));

});

gulp.task('scripts-js', function() {

  return gulp.src(['assets/scripts/**/*.js'])
    .pipe(concat('application-coffee.js'))
    .pipe(gulp.dest('dist/scripts'));

});

gulp.task('scripts', ['scripts-js', 'scripts-coffee'], function() {

  var re = gulp.src([
    'dist/scripts/application-js.js', 'dist/scripts/application-coffee.js'
  ])
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));

  del(['dist/scripts/application-js.js', 'dist/scripts/application-coffee.js']);

  return re;

});

PS:

ここで使用されたノードモジュールと機能:

// Load plugins
var gulp = require('gulp'),
    uglify = require('gulp-uglify'),
    rename = require('gulp-rename'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    plumber = require('gulp-plumber'),
    merge = require('ordered-merge-stream'),
    replace = require('gulp-replace'),
    del = require('del'),
    gulpif = require('gulp-if'),
    gulputil = require('gulp-util'),
    coffee = require('gulp-coffee'),
    coffeelint = require('gulp-coffeelint),
    lintThreshold = require('gulp-coffeelint-threshold');

var lintThresholdHandler = function(numberOfWarnings, numberOfErrors) {
  var msg;
  gulputil.beep();
  msg = 'CoffeeLint failure; see above. Warning count: ';
  msg += numberOfWarnings;
  msg += '. Error count: ' + numberOfErrors + '.';
  gulputil.log(msg);
};
var swallowError = function(err) {
  gulputil.log(err.toString());
  this.emit('end');
};

このコメントについてはまだ改善が見られます。速度比較と同様に、.jsファイルのみのリンク(縮小または3Dパーティーライブラリ、またはbower_componentsからのlibを除く)。しかし、基本的に、Google.comによるこの盗聴を調整して解決するのは簡単です
Roman M. Kos 2015

3

グローバルリスナーをタスクに追加し、意味のあるメッセージを表示できるため、gulp plumberを使用するのが好きです。

var plumber = require('gulp-plumber');

gulp.task('compile-scss', function () {
    gulp.src('scss/main.scss')
        .pipe(plumber())
        .pipe(sass())
        .pipe(autoprefixer())
        .pipe(cssnano())
        .pipe(gulp.dest('css/'));
});

リファレンス:https : //scotch.io/tutorials/prevent-errors-from-crashing-gulp-watch


2

https://github.com/gulpjs/gulp/issues/71の回避策として、次のハックを実装しました。

// Workaround for https://github.com/gulpjs/gulp/issues/71
var origSrc = gulp.src;
gulp.src = function () {
    return fixPipe(origSrc.apply(this, arguments));
};
function fixPipe(stream) {
    var origPipe = stream.pipe;
    stream.pipe = function (dest) {
        arguments[0] = dest.on('error', function (error) {
            var state = dest._readableState,
                pipesCount = state.pipesCount,
                pipes = state.pipes;
            if (pipesCount === 1) {
                pipes.emit('error', error);
            } else if (pipesCount > 1) {
                pipes.forEach(function (pipe) {
                    pipe.emit('error', error);
                });
            } else if (dest.listeners('error').length === 1) {
                throw error;
            }
        });
        return fixPipe(origPipe.apply(this, arguments));
    };
    return stream;
}

それをgulpfile.jsに追加して、次のように使用します。

gulp.src(src)
    // ...
    .pipe(uglify({compress: {}}))
    .pipe(gulp.dest('./dist'))
    .on('error', function (error) {
        console.error('' + error);
    });

これは、私にとって最も自然なエラー処理のように感じられます。エラーハンドラがまったくない場合は、エラーがスローされます。ノードv0.11.13でテスト済み。


2

これに対する簡単な解決策はgulp watch、Bash(またはsh)シェル内に無限ループを配置することです。

while true; do gulp; gulp watch; sleep 1; done

JavaScriptを編集するときは、このコマンドの出力を画面の表示領域に保持してください。編集結果がエラーになると、Gulpはクラッシュし、スタックトレースを出力し、1秒待ってから、ソースファイルの監視を再開します。その後、構文エラーを修正すると、Gulpは、通常の出力を印刷するか、再度クラッシュ(再開)して、編集が成功したかどうかを示します。

これはLinuxまたはMac端末で機能します。Windowsを使用している場合は、CygwinまたはUbuntu Bash(Windows 10)を使用します。


これは何語?また、これには、推奨されるソリューションよりもメリットがありますか?
George Mauer 2016年

Bash / shで書かれています。他のソリューションよりも必要なコードが少なく、覚えやすく、実装も簡単です。
Jesse Hogan、

そのbashとこれに関する他の考えを回答に編集できますか?配管工よりも簡単であることに同意しませんが、有効な(クロスプラットフォームではないにしても)アプローチです。最初は投票したのは、それがどの言語であったかさえ明確ではなく、回答を編集しない限り投票を変更できないためです。
George Mauer、2016年

1
したがって、ストリームをクラッシュさせてプロセス全体を再起動する方が、単純にエラーをキャッチするのではなく、無限ループで何をしているのかによってかなり時間がかかる場合があります。少し気になるようです。コードが少ないと言えば、配管工をタスクに追加するには16文字必要ですが、ソリューションではを数えずに36文字かかりますgulp watch
Balthazar 2016年

フィードバックのおかげで、@GeorgeMauer、私が編集を作り、それがで動作環境/プラットフォームについて書きました。
ジェシー・ホーガン

1

活字

これは私のために働いたものです。私は処理しTypescript、(thisキーワードとのaovidの混乱を避けるために)関数を分離しましたless。これも動作しJavascriptます。

var gulp = require('gulp');
var less = require('gulp-less');

gulp.task('less', function() {
    // writing a function to avoid confusion of 'this'
    var l = less({});
    l.on('error', function(err) {
        // *****
        // Handle the error as you like
        // *****
        l.emit('end');
    });

    return gulp
        .src('path/to/.less')
        .pipe(l)
        .pipe(gulp.dest('path/to/css/output/dir'))
})

これで、watch .lessファイルを作成してerrorが発生しても、はwatch停止せず、新しい変更はのように処理されますless task

:私は試してみましたl.end();。ただし、機能しませんでした。ただし、l.emit('end');完全に機能します。

この助けを願っています。幸運を。


1

これは私にとってうまくいった->

var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('sass', function(){
    setTimeout(function(){
        return gulp.src('sass/*.sass')
        .pipe(sass({indentedSyntax: true}))
        .on('error', console.error.bind(console))
        .pipe(gulp.dest('sass'));
    }, 300);
});



gulp.task('watch', function(){
    gulp.watch('sass/*.sass', ['sass']);
});

gulp.task('default', ['sass', 'watch'])

.on( 'error'、console.error.bind(console))行を追加しましたが、ルートとしてgulpコマンドを実行する必要がありました。私はphpアプリケーションでnode gulpを実行しているので、1つのサーバーに複数のアカウントがあるので、rootとしてgulpを実行していなかったために構文エラーでgulpが壊れる問題に遭遇しました...配管工と私がrootとして実行した場合、ここでの他の答えは私にとってうまくいきました。回答については、Accio Code https://www.youtube.com/watch?v=iMR7hq4ABOwのクレジットをご覧ください。彼は、エラーを処理することで、エラーがどの行にあり、コンソールに何があるかを判断するのに役立つだけでなく、構文エラーで壊れるのを防ぐこともできると述べました。彼はそれが軽量の修正のようなものだったので、あなたが探しているものにうまくいくかどうかわかりません。とはいえ、すぐに修正できます。これが誰かを助けることを願っています!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.