Mencegah kesalahan dari memecahkan / menabrak jam tangan

178

Saya menjalankan tegukan 3.6.2 dan memiliki tugas berikut yang telah diatur dari sampel online

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

Setiap kali ada kesalahan dalam jam tangan CoffeeScript saya berhenti - jelas bukan yang saya inginkan.

Seperti yang direkomendasikan di tempat lain saya mencoba ini

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

tapi sepertinya itu tidak berhasil.

Apa yang saya lakukan salah?


Menanggapi jawaban @ Aperçu saya memodifikasi swallowErrormetode saya dan mencoba yang berikut:

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

Mulai ulang, lalu buat kesalahan sintaksis dalam file kopi saya. Masalah yang sama:

[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
sumber
3
lihat resep tegukan resmi di github.com/gulpjs/gulp/tree/master/docs/recipes yang memiliki resep untuk ... menggabungkan-stream-ke-menangani-kesalahan menggunakan stream-combiner2 ini adalah jawaban resmi!
danday74

Jawaban:

257

swallowErrorFungsi Anda akan terlihat seperti ini:

function swallowError (error) {

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

  this.emit('end')
}

Saya pikir Anda harus mengikat fungsi ini errorjika ada tugas yang jatuh, bukan watchtugas, karena bukan itu masalahnya, Anda harus mengatur kesalahan panggil balik ini pada setiap tugas yang mungkin gagal, seperti plugin yang rusak saat Anda memiliki melewatkan ;atau sesuatu yang lain, untuk mencegahwatch tugas berhenti.

Contoh:

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

Sebagai alternatif, jika Anda tidak keberatan untuk memasukkan modul lain, Anda dapat menggunakan fungsi log dari gulp-util agar Anda tidak mendeklarasikan fungsi tambahan di gulpfile:

.on('error', gutil.log)

Tetapi saya dapat merekomendasikan untuk melihat pada plugin gulp-tukang ledeng yang mengagumkan , yang digunakan untuk menghapus onerrorhandler dari erroracara tersebut, menyebabkan pecahnya aliran. Ini sangat mudah digunakan dan menghentikan Anda dari menangkap semua tugas yang mungkin gagal.

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

Info lebih lanjut tentang ini pada artikel ini oleh pembuat plugin yang bersangkutan.

Balthazar
sumber
Saya menghargai bantuan Anda. Lihat hasil edit saya. Saya pikir saya melakukan apa yang Anda katakan dan itu masih tidak berhasil
George Mauer
2
Anda mungkin ingin mengedit jawaban Anda untuk mencerminkan hal terakhir yang benar untuk dilakukan sehingga siapa pun yang menemukan ini di masa depan tidak harus membaca rantai komentar.
George Mauer
1
Ini semua baik dan bagus, tetapi mengapa saya harus menulis penangan kesalahan saya sendiri? Seluruh alasan saya menggunakan tegukan atau gerutuan atau alat preprocessing apa pun, adalah bahwa itu melakukan pekerjaan kotor untuk saya. Kesalahan sintaksis di suatu tempat dalam kode saya (yang pasti akan terjadi) tidak boleh membuat seluruh sistem terhenti. Bandingkan ini dengan GUI Prepros (preprocessor lain) - alat ini memberi tahu Anda persis di mana kesalahan Anda, dan tidak menggantung atau berhenti ketika ada sesuatu yang salah.
Kokodoko
1
luar biasa bahwa tidak ada seorang pun di seluruh yang menyebutkan steam-combiner2 walaupun itu adalah resep tegukan resmi! tukang ledeng juga baik tetapi saya selalu lebih suka mengikuti resep tegukan, resep tegukan terus diperbarui dengan tegukan dan dapat dilihat di github.com/gulpjs/gulp/tree/master/docs/recipes
danday74
1
Menghadapi teka-teki yang sama, saya memutuskan untuk menggunakan pembungkus gulp.watch()yang menambahkan .on('error', function() { this.emit('end') })pada hasil fungsi arloji, karena secara khusus tugas arloji yang saya ingin tangguh untuk menutup telepon. Bekerja dengan sangat baik, dan tugas-tugas individual yang gagal masih mencetak pesan kesalahan mereka sendiri. Lihat kode: github.com/specious/specious.github.io/commit/f8571d28
tknomad
20

Contoh di atas tidak berhasil untuk saya. Namun berikut ini:

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']);
});
pengguna1491819
sumber
Ini bagus, tetapi juga baik untuk memberi tahu jika ada kesalahan (saat ini hanya kesalahan log di terminal)
raison
4

Dengan satu format file

(mis .: * .kopi saja)

Jika Anda ingin bekerja hanya dengan satu format file, maka gulp-plumbersolusi Anda.

Misalnya kaya kesalahan yang ditangani dan peringatan untuk skrip kopi:

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

Dengan berbagai jenis format file

(mis: * .kopi dan * .js pada saat bersamaan)

Tetapi jika Anda tidak akan bekerja dengan banyak jenis format file (misalnya: *.jsdan *.coffee), maka saya akan memposting solusi saya.

Saya hanya akan memposting kode penjelasan sendiri di sini, dengan beberapa deskripsi sebelumnya.

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

Saya menghadapi masalah dengan gulp-plumberdan gulp-ifmenggunakangulp.watch(...

Lihat masalah terkait di sini: https://github.com/floatdrop/gulp-plumber/issues/23

Jadi pilihan terbaik bagi saya adalah:

  • Setiap bagian sebagai file, dan digabung setelahnya . Buat beberapa tugas yang dapat memproses setiap bagian dalam file yang terpisah (seperti halnya dengusan), dan menggabungkannya
  • Setiap bagian sebagai aliran, dan menggabungkan aliran setelah . Menggabungkan dua aliran menggunakan merge-stream(yang dibuat dari event-stream) menjadi satu dan melanjutkan pekerjaan (saya mencoba yang pertama, dan itu berfungsi dengan baik bagi saya, jadi ini solusi yang lebih cepat daripada yang sebelumnya)

Setiap bagian sebagai aliran, dan menggabungkan aliran setelah

Dia adalah bagian utama dari kode saya:

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

Setiap bagian sebagai file, dan digabung setelahnya

Jika untuk memisahkan ini menjadi bagian-bagian, maka di setiap bagian harus ada file hasil yang dibuat. Untuk ex .:

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:

Di sini simpul modul dan fungsi yang digunakan:

// 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
sumber
Saya masih melihat peningkatan untuk komentar ini. Menyukai perbandingan kecepatan, dan menautkan hanya file .js (tidak termasuk pustaka pihak minified atau 3d, atau lib dari bower_components). Tetapi pada dasarnya mudah untuk menyesuaikan dan menyelesaikan masalah mengendus ini oleh Google.com
Roman M. Koss
3

Saya suka menggunakan tukang ledeng karena dapat menambah pendengar global ke tugas dan memiliki pesan yang berarti ditampilkan.

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

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

Sameeksha Kumari
sumber
2

Saya telah menerapkan peretasan berikut sebagai solusi untuk 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;
}

Tambahkan ke gulpfile.js Anda dan gunakan seperti itu:

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

Ini terasa seperti penanganan kesalahan yang paling alami bagi saya. Jika tidak ada penangan kesalahan sama sekali, itu akan melempar kesalahan. Diuji dengan Node v0.11.13.

Joel Richard
sumber
2

Solusi sederhana untuk ini adalah dengan memasukkan gulp watchloop tak terbatas dalam shell Bash (atau sh).

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

Simpan output dari perintah ini di area yang terlihat di layar Anda saat Anda mengedit JavaScript. Ketika hasil edit Anda menghasilkan kesalahan, Gulp akan macet, cetak jejak tumpukannya, tunggu sebentar, dan lanjutkan menonton file sumber Anda. Anda kemudian dapat memperbaiki kesalahan sintaksis, dan Gulp akan menunjukkan apakah pengeditannya berhasil atau tidak dengan mencetak output normalnya, atau menabrak (lalu melanjutkan) lagi.

Ini akan bekerja di terminal Linux atau Mac. Jika Anda menggunakan Windows, gunakan Cygwin atau Ubuntu Bash (Windows 10).

Jesse Hogan
sumber
Bahasa apa ini? Juga, apakah ada manfaatnya dibandingkan solusi yang disarankan?
George Mauer
Itu ditulis dalam Bash / sh. Ini membutuhkan lebih sedikit kode daripada solusi lain dan lebih mudah diingat dan diimplementasikan.
Jesse Hogan
Bisakah Anda mengedit fakta bahwa bash dan pemikiran Anda yang lain tentang ini menjadi jawaban Anda? Saya tidak setuju bahwa itu lebih mudah daripada tukang ledeng, tetapi pendekatan yang valid (jika tidak lintas platform). Saya menolak pada awalnya karena tidak jelas bahasa apa itu dan saya tidak dapat mengubah suara saya kecuali Anda mengedit jawabannya.
George Mauer
1
Jadi Anda lebih suka menabrak aliran dan memulai ulang seluruh proses yang mungkin memerlukan beberapa tergantung pada apa yang Anda lakukan dengan loop tak terbatas daripada hanya menangkap kesalahan? Sepertinya agak mengganggu saya. Dan berbicara tentang kode lebih sedikit, Anda membutuhkan 16 karakter untuk menambahkan tukang ledeng ke tugas Anda sedangkan solusi Anda membutuhkan 36 tanpa menghitung gulp watch.
Balthazar
Terima kasih atas umpan baliknya, @GeorgeMauer, saya melakukan pengeditan dan menulis tentang lingkungan / platform kerjanya.
Jesse Hogan
1

Naskah

Inilah yang bekerja untuk saya. Saya bekerja dengan Typescriptdan memisahkan fungsi (untuk bingung dengan thiskata kunci) untuk menangani less. Ini bekerja dengan Javascriptbaik.

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

Sekarang, ketika Anda watch .lessfile, dan suatu errorterjadi, watchtidak akan berhenti dan perubahan baru akan diproses sesuai Anda less task.

CATATAN : Saya mencoba dengan l.end();; Namun, itu tidak berhasil. Namun, l.emit('end');benar-benar berfungsi.

Semoga bantuan ini. Semoga berhasil.

Akash
sumber
1

Ini bekerja untuk saya ->

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

Saya baru saja menambahkan baris .on ('error', console.error.bind (console)), tetapi saya harus menjalankan perintah gulp sebagai root. Saya menjalankan simpul tegukan pada aplikasi php jadi saya memiliki beberapa akun di satu server, itulah sebabnya saya mengalami masalah teguran pada kesalahan sintaks karena saya tidak menjalankan tegukan sebagai root ... Mungkin tukang ledeng dan beberapa jawaban lain di sini akan bekerja untuk saya jika saya berlari sebagai root. Kredit ke Kode Accio https://www.youtube.com/watch?v=iMR7hq4ABOw untuk jawabannya. Dia mengatakan bahwa dengan menangani kesalahan itu membantu Anda untuk menentukan baris apa kesalahan itu aktif dan apa yang ada di konsol, tetapi juga berhenti menelan mematahkan kesalahan sintaks. Dia mengatakan itu semacam perbaikan ringan, jadi tidak yakin apakah itu akan berhasil untuk apa yang Anda cari. Perbaikan cepat, layak dicoba. Semoga ini bisa membantu seseorang!

kiko carisse
sumber