防止错误破坏/损坏gulp手表


180

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

重新启动,然后在我的coffee文件中创建语法错误。相同的问题:

[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 2015年

Answers:


261

您的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-utillog函数,以防止您在自己的函数中声明其他函数: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'))

有关插件的创建者在本文上提供了有关此内容的更多信息。


我感谢您的帮助。看到我的编辑。我想我正在按照您的意思说,但仍然不起作用
George Mauer 2014年

2
您可能希望编辑您的答案以反映最终的正确做法,以便将来找到此答案的任何人都不必阅读评论链。
乔治·莫尔

1
这一切都很好,但是为什么我必须编写自己的错误处理程序?我之所以使用gulp或grunt或任何预处理工具,是因为它为我做了肮脏的工作。我的代码中某处的语法错误(一定会发生)不应使整个系统停顿下来。将此与Prepros(另一个预处理器)的GUI进行比较-该工具可以准确地告诉您错误的位置,并且在出现问题时不会挂起或退出。
Kokodoko

1
令人惊讶的是,尽管这是官方的口水配方,但没有人提到过Steam-combiner2!水管工也不错,但我总是喜欢遵循gulp食谱,gulp食谱由gulp
danday74

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

使用一种格式的文件

(例如:*。仅咖啡)

如果您只想使用一种格式的文件,那么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-plumbergulp-if使用的问题gulp.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;

});

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. Koss,2015年


2

我已经实现了以下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;
}

将其添加到您的gulpfile.js中,并像这样使用它:

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

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


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


这是什么语言?此外,与建议的解决方案相比,这样做有什么好处吗?
乔治·莫尔

它是用Bash / sh编写的。与其他解决方案相比,它所需的代码更少,并且更容易记住和实现。
Jesse Hogan

您能否将它的抨击和您对此的其他想法编辑为答案?我不同意它比管道工容易,但它是一种有效的方法(如果不是跨平台的话)。我最初投了反对票,是因为甚至不清楚它的语言,而且除非您编辑答案,否则我无法更改投票。
乔治·莫尔

1
因此,您更喜欢使流崩溃并重新启动整个过程,这可能要花很多时间,具体取决于您使用无限循环执行的操作,而不是简单地捕获错误?似乎有点困扰我。说到更少的代码,它需要16个字符才能将plumber添加到您的任务中,而您的解决方案需要36个字符而不计算gulp watch
Balthazar

感谢您的反馈,@GeorgeMauer,我所做的编辑,并写了关于环境/平台上,工作的地方。
杰西·霍根

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');完全可以。

希望对您有所帮助。祝好运。


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))行,但是我必须以root用户身份运行gulp命令。我在php应用程序上运行节点gulp,所以我在一台服务器上有多个帐户,这就是为什么我遇到gulp打破语法错误的问题,因为我没有以root身份运行gulp ...也许是水管工和一些如果我以root身份运行,这里的其他答案对我有用。将答案记入Accio Code https://www.youtube.com/watch?v=iMR7hq4ABOw。他说,通过处理错误,它可以帮助您确定错误所在的行以及控制台中的错误,还可以防止gulp破坏语法错误。他说,这只是一种轻巧的解决方案,所以不确定是否能满足您的需求。快速修复,值得一试。希望这对某人有帮助!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.