node.js 防止错误破坏/崩溃 gulp 手表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23971388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 17:25:57  来源:igfitidea点击:

Prevent errors from breaking / crashing gulp watch

node.jsgulp

提问by George Mauer

I'm running gulp 3.6.2 and have the following task that was set up from a sample online

我正在运行 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']);
});

Any time there's an error in my CoffeeScript gulp watch stops - obviously not what I want.

任何时候我的 CoffeeScript gulp 手表出现错误都会停止 - 显然不是我想要的。

As recommended elsewhere I tried this

按照其他地方的建议,我尝试了这个

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

but it doesn't seem to work.

但它似乎不起作用。

What am I doing wrong?

我究竟做错了什么?



In response to @Aper?u's answer I modified my swallowErrormethod and tried the following instead:

为了回应@Aper?u 的回答,我修改了我的swallowError方法并尝试了以下方法:

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

Restarted, and then created a syntax error in my coffee file. Same issue:

重新启动,然后在我的咖啡文件中创建了一个语法错误。同样的问题:

[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)

回答by Balthazar

Your swallowErrorfunction should look like this:

您的swallowError函数应如下所示:

function swallowError (error) {

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

  this.emit('end')
}

I think you have to bind this function on the errorevent of the task that was falling, not the watchtask, because that's not where comes the problem, you should set this error callback on each task that may fail, like plugins that breaks when you have missed a ;or something else, to prevent watchtask to stop.

我认为你必须error在任务下降的事件上绑定这个函数,而不是watch任务,因为这不是问题的出处,你应该在每个可能失败的任务上设置这个错误回调,比如插件在你有错过了一个;或者别的什么,防止watch任务停止。

Examples :

例子 :

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

Alternately, if you don't mind to include another module, you can use the logfunction of gulp-utilto keep you from declare an extra function in your gulpfile:

或者,如果您不介意包含另一个模块,您可以使用gulp-utillog功能来防止您在您的.gulpfile

.on('error', gutil.log)


But I may recommend having a look at the awesome gulp-plumberplugin, which is used to remove the onerrorhandler of the errorevent, causing the break of the streams. It's very simple to use and it stops you from catch all the tasks that may fail.

但我可能会推荐看看很棒的gulp-plumber插件,它用于删除事件的onerror处理程序error,导致流中断。它使用起来非常简单,它可以阻止您捕获所有可能失败的任务。

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

More info about this on this articleby the creator of the concerned plugin.

有关此插件的创建者在本文中的更多信息。

回答by user1491819

The above examples didn't work for me. The following did though:

上面的例子对我不起作用。但以下做了:

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

回答by Roman M. Koss

With one format of files

使用一种格式的文件

(ex: *.coffee only)

(例如:*.coffee only)

If you want to work only with one format of files, then gulp-plumberis your solution.

如果您只想处理一种格式的文件,那么这gulp-plumber就是您的解决方案。

For example rich handled errors and warning for coffeescripting:

例如,咖啡脚本的丰富处理错误和警告:

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

With multiple types of file formats

具有多种类型的文件格式

(ex: *.coffee and *.js at same time)

(例如:*.coffee 和 *.js 同时)

But if you won't to work with multiple types of file formats (for example: *.jsand *.coffee), than i will post my solution.

但是,如果您不想使用多种类型的文件格式(例如:*.js*.coffee),那么我将发布我的解决方案。

I will just post a self explanatory code over here, with some description before.

我将在这里发布一个自我解释的代码,之前有一些描述。

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

I faced the issue with gulp-plumberand gulp-ifusing gulp.watch(...

我遇到gulp-plumbergulp-if使用的问题gulp.watch(...

See related issue here: https://github.com/floatdrop/gulp-plumber/issues/23

在此处查看相关问题:https: //github.com/floatdrop/gulp-plumber/issues/23

So the best option for me was:

所以对我来说最好的选择是:

  • Each part as file, and concatenate after. Create multiple tasks that can process each part in separate file (like grunt does), and concatenate them
  • Each part as stream, and merge streams after. Merge two streams using merge-stream(that was made from event-stream) into one and continue the job (i tried that first, and it work fine for me, so it is faster solution than previous one)
  • 每个部分作为文件,并在. 创建多个任务,可以在单独的文件中处理每个部分(就像 grunt 一样),并将它们连接起来
  • 每个部分作为流,并在 之后合并流。合并使用两个流merge-stream(即从制造event-stream)合并为一个,并继续工作(我想,第一,它的工作对我很好,所以它是更快的解决方案比以前的一个)


Each part as stream, and merge streams after

每个部分作为流,然后合并流

Her is the main part of my code:

她是我代码的主要部分:

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


Each part as file, and concatenate after

每个部分作为文件,并在之后连接

If to separate this into parts, then in each part there should be a result file created. For 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;

});

P.S.:

PS:

Here node modules and functions that were used:

这里使用的节点模块和功能:

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

回答by Sameeksha Kumari

I like to use gulp plumber because it can add a global listener to a task and have a meaningful message displayed.

我喜欢使用 gulp 管道工,因为它可以向任务添加全局侦听器并显示有意义的消息。

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

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

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

回答by Jesse Hogan

A simple solution to this is to put gulp watchin an infinite loop within a Bash (or sh) shell.

对此的一个简单解决方案是gulp watch在 Bash(或 sh)shell 中放入一个无限循环。

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

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

Keep the output of this command in a visible area on your screen as you edit your JavaScript. When your edits result in an error, Gulp will crash, print its stack trace, wait for a second, and resume watching your source files. You can then correct the syntax error, and Gulp will indicate whether or not the edit was a success by either printing out it's normal output, or crashing (then resuming) again.

编辑 JavaScript 时,将此命令的输出保留在屏幕上的可见区域。当您的编辑导致错误时,Gulp 将崩溃,打印其堆栈跟踪,等待一秒钟,然后继续查看您的源文件。然后您可以更正语法错误,Gulp 将通过打印出正常输出或再次崩溃(然后恢复)来指示编辑是否成功。

This will work in a Linux or Mac terminal. If you are using Windows, use Cygwin or Ubuntu Bash (Windows 10).

这将在 Linux 或 Mac 终端中工作。如果您使用的是 Windows,请使用 Cygwin 或 Ubuntu Bash (Windows 10)。

回答by Joel Richard

I have implemented the following hack as a workaround for https://github.com/gulpjs/gulp/issues/71:

我已经实施了以下 hack 作为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;
}

Add it to your gulpfile.js and use it like that:

将它添加到你的 gulpfile.js 并像这样使用它:

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

This feels like the most natural error handling to me. If there is no error handler at all, it will throw an error. Tested with Node v0.11.13.

这对我来说是最自然的错误处理。如果根本没有错误处理程序,它将抛出错误。使用 Node v0.11.13 测试。

回答by Akash

Typescript

打字稿

This is what worked for me. I work with Typescriptand separated the function (to aovid confusion with thiskeyword) to handle less. This works with Javascriptas well.

这对我有用。我使用Typescript并分离了函数(避免与this关键字混淆)来处理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'))
})

Now, when you watch.lessfiles, and an erroroccurs, the watchwill not stop and new changes will processed as per your less task.

现在,当您watch.less归档并error发生时,watch不会停止并且新的更改将按照您的less task.

NOTE: I tried with l.end();; however, it did not work. However, l.emit('end');totally works.

注意:我试过l.end();; 然而,它不起作用。但是,l.emit('end');完全有效。

Hope this help. Good Luck.

希望这有帮助。祝你好运。

回答by kiko carisse

This worked for me ->

这对我有用->

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

I just added the .on('error', console.error.bind(console)) line, but I had to run the gulp command as root. I'm running node gulp on a php application so I have multiple accounts on one server, which is why I ran into the issue of gulp breaking on syntax errors because I was not running gulp as root... Maybe plumber and some of the other answers here would have worked for me if I ran as root. Credit to Accio Code https://www.youtube.com/watch?v=iMR7hq4ABOwfor the answer. He said that by handling the error it helps you to determine what line the error is on and what it is in the console, but also stops gulp from breaking on syntax error. He said it was kind of a light weight fix, so not sure if it will work for what you are looking for. Quick fix though, worth a shot. Hope this helps someone!

我刚刚添加了 .on('error', console.error.bind(console)) 行,但我必须以 root 身份运行 gulp 命令。我在 php 应用程序上运行 node gulp,所以我在一台服务器上有多个帐户,这就是为什么我遇到了 gulp 因语法错误而中断的问题,因为我没有以 root 身份运行 gulp ......也许水管工和一些如果我以 root 身份运行,这里的其他答案对我有用。归功于 Accio Code https://www.youtube.com/watch?v=iMR7hq4ABOw的答案。他说,通过处理错误,它可以帮助您确定错误发生在哪一行以及它在控制台中的内容,而且还可以阻止 gulp 因语法错误而中断。他说这是一种轻量级的修复,所以不确定它是否适合你正在寻找的东西。快速修复,值得一试。希望这可以帮助某人!