防止突破/崩溃gulp手表的错误

时间:2014-05-31 14:50:04

标签: node.js gulp

我正在运行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手表停止出现错误 - 显然不是我想要的。

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

但它似乎不起作用。

我做错了什么?


为了回应@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)

8 个答案:

答案 0 :(得分:254)

您的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 日志功能来阻止您声明gulpfile中的额外功能:

.on('error', gutil.log)

但我可能会建议您查看令人敬畏的 gulp-plumber 插件,该插件用于删除onerror事件的error处理程序,从而导致打破了溪流。它使用起来非常简单,它可以阻止你捕获可能失败的所有任务。

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

有关插件的创建者在this article上有关此内容的详细信息。

答案 1 :(得分: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']);
});

答案 2 :(得分:4)

使用一种格式的文件

(例如:* .coffee仅限)

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

例如丰富的处理错误和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' }));
});

具有多种类型的文件格式

(例如:* .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-ifgulp.watch(...的问题

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

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

  • 每个部分都作为文件,并在之后连接。创建可以在单独文件中处理每个部分的多个任务(如grunt),并将它们连接起来
  • 每个部分都作为流,并在之后合并流。使用merge-stream(由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;

});

P.S:

这里使用的节点模块和函数:

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

答案 3 :(得分:3)

我喜欢使用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/'));
});

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

答案 4 :(得分: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);
    });

这对我来说感觉就像是最自然的错误处理。如果根本没有错误处理程序,则会抛出错误。使用Node v0.11.13进行测试。

答案 5 :(得分:2)

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

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

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

这适用于Linux或Mac终端。如果您使用的是Windows,请使用Cygwin或Ubuntu Bash(Windows 10)。

答案 6 :(得分:1)

<强>打字稿

这对我有用。我使用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'))
})

现在,当您watch .less个文件发生error时,watch将不会停止,系统会根据您的less task处理新的更改

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

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

答案 7 :(得分:1)

这对我有用 - &gt;

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(&#39;错误&#39;,console.error.bind(console)) 线,但我不得不跑     吞 以root身份命令。我在php应用程序上运行node gulp所以我在一台服务器上有多个帐户,这就是为什么我遇到了gulp打破语法错误的问题,因为我没有以root身份运行gulp ...也许管道工和一些如果我以root身份运行,这里的其他答案对我有用。 感谢Accio代码https://www.youtube.com/watch?v=iMR7hq4ABOw获得答案。他说,通过处理错误,它可以帮助您确定错误在哪个行以及控制台中的错误,但也可以阻止gulp打破语法错误。他说这是一种轻量级修复,所以不确定它是否适用于你正在寻找的东西。快速修复,值得一试。希望这有助于某人!