Verhindern Sie, dass Fehler die Schluckuhr brechen / abstürzen

177

Ich verwende gulp 3.6.2 und habe die folgende Aufgabe, die anhand eines Beispiels online eingerichtet wurde

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']);
});

Jedes Mal, wenn ein Fehler in meiner CoffeeScript-Schluckuhr auftritt, stoppt sie - offensichtlich nicht das, was ich will.

Wie an anderer Stelle empfohlen, habe ich dies versucht

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

aber es scheint nicht zu funktionieren.

Was mache ich falsch?


Als Antwort auf die Antwort von @ Aperçu habe ich meine swallowErrorMethode geändert und stattdessen Folgendes versucht:

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

Neustart und dann ein Syntaxfehler in meiner Kaffeedatei erstellt. Gleicher Fehler:

[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)
George Mauer
quelle
3
Siehe die offiziellen Schluckrezepte unter github.com/gulpjs/gulp/tree/master/docs/recipes , die ein Rezept für ... das Kombinieren von Streams-to-Handle-Fehlern mit Stream-Combiner2 enthalten. Dies ist die offizielle Antwort!
danday74

Antworten:

257

Ihre swallowErrorFunktion sollte folgendermaßen aussehen:

function swallowError (error) {

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

  this.emit('end')
}

Ich denke, Sie müssen diese Funktion für den errorFall binden, dass die Aufgabe heruntergefallen ist, nicht für die watchAufgabe, da hier nicht das Problem auftritt. Sie sollten diesen Fehlerrückruf für jede Aufgabe festlegen, die möglicherweise fehlschlägt, z. B. für Plugins, die bei Bedarf unterbrochen werden habe ein ;oder etwas anderes verpasst , um zu verhindern, dass die watchAufgabe gestoppt wird.

Beispiele:

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'))
})

Wenn es Ihnen nichts ausmacht, ein anderes Modul einzuschließen , können Sie alternativ die Protokollfunktion von gulp-util verwenden , um zu verhindern , dass Sie eine zusätzliche Funktion in Ihrem gulpfile:

.on('error', gutil.log)

Aber ich kann empfehlen, einen Blick auf das fantastische Gulp-Plumber- Plugin zu werfen, mit dem der onerrorHandler des errorEreignisses entfernt wird, wodurch die Streams unterbrochen werden. Es ist sehr einfach zu bedienen und verhindert, dass Sie alle Aufgaben abfangen, die möglicherweise fehlschlagen.

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

Weitere Informationen hierzu finden Sie in diesem Artikel des Erstellers des betreffenden Plugins.

Balthazar
quelle
Ich schätze Ihre Hilfe. Siehe meine Bearbeitung. Ich denke, ich mache was du sagst und es funktioniert immer noch nicht
George Mauer
2
Möglicherweise möchten Sie Ihre Antwort so bearbeiten, dass sie die endgültige Richtigkeit widerspiegelt. Jeder, der dies in Zukunft findet, muss die Kommentarkette nicht lesen.
George Mauer
1
Das ist alles schön und gut, aber warum sollte ich meine eigenen Fehlerbehandler schreiben müssen? Der ganze Grund, warum ich Schluck oder Grunzen oder was auch immer für ein Vorverarbeitungswerkzeug benutze, ist, dass es die Drecksarbeit für mich erledigt. Ein Syntaxfehler irgendwo in meinem Code (der zwangsläufig auftreten wird) sollte nicht das gesamte System zum Stillstand bringen. Vergleichen Sie dies mit der GUI von Prepros (einem anderen Präprozessor) - dieses Tool zeigt Ihnen genau an, wo Ihr Fehler liegt, und hängt nicht auf oder wird nicht beendet, wenn etwas nicht stimmt.
Kokodoko
1
Erstaunlich, dass niemand Steam-Combiner2 erwähnt hat, obwohl es das offizielle Schluckrezept ist! Klempner auch gut, aber ich ziehe es immer vor, Schluckrezepte zu befolgen, die Schluckrezepte werden von Schluck auf dem neuesten Stand gehalten und können unter github.com/gulpjs/gulp/tree/master/docs/recipes
danday74
1
Mit Blick auf das gleiche Rätsel, entschied ich mich für einen Wrapper um mit , gulp.watch()dass ein fügt .on('error', function() { this.emit('end') })das Ergebnis der Uhr - Funktion, wie sie speziell die Uhr Aufgabe sind , dass ich zu Aufhängen elastisch machen will. Funktioniert sehr gut und die einzelnen fehlgeschlagenen Aufgaben drucken immer noch ihre eigenen Fehlermeldungen. Siehe den Code: github.com/specious/specious.github.io/commit/f8571d28
tknomad
20

Die obigen Beispiele haben bei mir nicht funktioniert. Folgendes geschah jedoch:

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']);
});
user1491819
quelle
Dies ist großartig, aber es wäre auch gut zu benachrichtigen, wenn ein Fehler aufgetreten ist (derzeit wird nur ein Fehler im Terminal protokolliert)
Existenzberechtigung
4

Mit einem Dateiformat

(Beispiel: * nur Kaffee)

Wenn Sie nur mit einem Dateiformat arbeiten möchten, gulp-plumberist dies Ihre Lösung.

Zum Beispiel reichhaltige Fehler und Warnungen beim Kaffeeskripten:

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' }));
});

Mit mehreren Arten von Dateiformaten

(Beispiel: * .coffee und * .js gleichzeitig)

Aber wenn Sie nicht mit mehreren Arten von Dateiformaten arbeiten möchten (zum Beispiel: *.jsund *.coffee), werde ich meine Lösung veröffentlichen.

Ich werde hier nur einen selbsterklärenden Code mit einer Beschreibung veröffentlichen.

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' }));
});

Ich habe mich dem Problem mit gulp-plumberund gulp-ifmit gestelltgulp.watch(...

Siehe verwandtes Problem hier: https://github.com/floatdrop/gulp-plumber/issues/23

Die beste Option für mich war also:

  • Jeder Teil als Datei und danach verketten . Erstellen Sie mehrere Aufgaben, die jedes Teil in einer separaten Datei verarbeiten können (wie dies bei grunt der Fall ist), und verketten Sie sie
  • Jeder Teil als Stream und Streams danach zusammenführen . Füge zwei Streams mit merge-stream(die daraus erstellt wurden event-stream) zu einem zusammen und setze den Job fort (ich habe das zuerst versucht, und es funktioniert gut für mich, daher ist es eine schnellere Lösung als die vorherige).

Jeder Teil als Stream und Streams danach zusammenführen

Sie ist der Hauptteil meines Codes:

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' }));
});

Jeder Teil als Datei und danach verketten

Wenn dies in Teile unterteilt werden soll, sollte in jedem Teil eine Ergebnisdatei erstellt werden. Zum Beispiel:

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:

Hier wurden Knotenmodule und Funktionen verwendet:

// 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');
};
Roman M. Koss
quelle
Ich sehe immer noch Verbesserungen für diese Kommentare. Wie Geschwindigkeitsvergleich und Link nur für .js-Dateien (ausgenommen minimierte Bibliotheken oder Bibliotheken von Drittanbietern oder Bibliotheken von bower_components). Aber im Grunde ist es einfach, dieses Schnüffeln von Google.com anzupassen und zu lösen
Roman M. Koss
3

Ich verwende gerne Schluck-Klempner, weil er einer Aufgabe einen globalen Listener hinzufügen und eine aussagekräftige Nachricht anzeigen kann.

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/'));
});

Referenz: https://scotch.io/tutorials/prevent-errors-from-crashing-gulp-watch

Sameeksha Kumari
quelle
2

Ich habe den folgenden Hack als Problemumgehung für https://github.com/gulpjs/gulp/issues/71 implementiert :

// 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;
}

Fügen Sie es Ihrer gulpfile.js hinzu und verwenden Sie es folgendermaßen:

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

Dies fühlt sich für mich wie die natürlichste Fehlerbehandlung an. Wenn überhaupt kein Fehlerbehandler vorhanden ist, wird ein Fehler ausgegeben. Getestet mit Node v0.11.13.

Joel Richard
quelle
2

Eine einfache Lösung hierfür besteht darin, gulp watcheine Endlosschleife innerhalb einer Bash- (oder sh-) Shell einzufügen.

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

Halten Sie die Ausgabe dieses Befehls in einem sichtbaren Bereich auf Ihrem Bildschirm, während Sie Ihr JavaScript bearbeiten. Wenn Ihre Änderungen zu einem Fehler führen, stürzt Gulp ab, druckt den Stack-Trace, wartet eine Sekunde und setzt die Überwachung Ihrer Quelldateien fort. Sie können dann den Syntaxfehler korrigieren, und Gulp zeigt an, ob die Bearbeitung erfolgreich war, indem Sie entweder die normale Ausgabe ausdrucken oder erneut abstürzen (und dann wieder aufnehmen).

Dies funktioniert in einem Linux- oder Mac-Terminal. Wenn Sie Windows verwenden, verwenden Sie Cygwin oder Ubuntu Bash (Windows 10).

Jesse Hogan
quelle
Welche Sprache ist das? Gibt es auch einen Vorteil gegenüber den vorgeschlagenen Lösungen?
George Mauer
Es ist in Bash / sh geschrieben. Es erfordert weniger Code als die anderen Lösungen und ist leichter zu merken und zu implementieren.
Jesse Hogan
Können Sie die Tatsache, dass es Bash und Ihre anderen Gedanken dazu in Ihre Antwort einfließen lassen? Ich bin nicht der Meinung, dass es einfacher als Klempner ist, aber es ist ein gültiger (wenn nicht plattformübergreifender) Ansatz. Ich habe anfangs abgelehnt, weil nicht einmal klar war, in welcher Sprache es war, und ich kann meine Stimme nur ändern, wenn Sie die Antwort bearbeiten.
George Mauer
1
Sie ziehen es also vor, den Stream zum Absturz zu bringen und den gesamten Prozess neu zu starten, was je nachdem, was Sie mit einer Endlosschleife tun, einige Zeit in Anspruch nehmen kann, anstatt nur den Fehler abzufangen? Scheint mir ein wenig störend. Wenn Sie von weniger Code sprechen, benötigen Sie 16 Zeichen, um Ihrer Aufgabe Klempner hinzuzufügen, während Ihre Lösung 36 Zeichen benötigt, ohne die zu zählen gulp watch.
Balthazar
Vielen Dank für das Feedback, @GeorgeMauer, ich habe die Änderungen vorgenommen und über die Umgebungen / Plattformen geschrieben, in denen es funktioniert.
Jesse Hogan
1

Typoskript

Das hat bei mir funktioniert. Ich arbeite mit Typescriptund trennte die zu behandelnde Funktion (um Verwechslungen mit thisSchlüsselwörtern zu vermeiden ) less. Dies funktioniert auch mit 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'))
})

Wenn Sie nun watch .lessDateien ablegen und ein errorEreignis auftritt, watchwird das nicht gestoppt und neue Änderungen werden gemäß Ihren Angaben verarbeitetless task .

HINWEIS : Ich habe es mit versucht l.end();; es hat jedoch nicht funktioniert. Jedoch,l.emit('end'); total.

Ich hoffe das hilft. Viel Glück.

Akash
quelle
1

Das hat bei mir funktioniert ->

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'])

Ich habe gerade die Zeile .on ('error', console.error.bind (console)) hinzugefügt, musste aber den Befehl gulp als root ausführen. Ich führe Node Gulp in einer PHP-Anwendung aus, daher habe ich mehrere Konten auf einem Server. Aus diesem Grund bin ich auf das Problem gestoßen, dass Gulp aufgrund von Syntaxfehlern unterbrochen wurde, weil ich Gulp nicht als Root ausgeführt habe ... Vielleicht Klempner und einige der andere Antworten hier hätten für mich funktioniert, wenn ich als root gelaufen wäre. Gutschrift auf den Accio-Code https://www.youtube.com/watch?v=iMR7hq4ABOw für die Antwort. Er sagte, dass es Ihnen durch die Behandlung des Fehlers hilft, festzustellen, in welcher Zeile sich der Fehler befindet und was sich in der Konsole befindet, aber auch verhindert, dass gulp bei einem Syntaxfehler bricht. Er sagte, es sei eine Art leichtes Update, also nicht sicher, ob es für das funktioniert, wonach Sie suchen. Schnelle Lösung, einen Versuch wert. Hoffe das hilft jemandem!

kiko carisse
quelle