防止错误破坏/崩溃 gulp watch
Posted
技术标签:
【中文标题】防止错误破坏/崩溃 gulp watch【英文标题】:Prevent errors from breaking / crashing gulp watch 【发布时间】:2014-07-21 04:54:47 【问题描述】:我正在运行 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 watch stop 出现错误 - 显然不是我想要的。
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)
【问题讨论】:
在github.com/gulpjs/gulp/tree/master/docs/recipes 上查看官方 gulp 食谱,其中有一个使用 stream-combiner2 组合流到处理错误的食谱,这是官方答案! 【参考方案1】:您的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 的 log 函数来防止你在你的gulpfile
:
.on('error', gutil.log)
但我可能建议您看看很棒的 gulp-plumber 插件,该插件用于删除 error
事件的 onerror
处理程序,从而导致流中断。它使用起来非常简单,它可以阻止您捕获所有可能失败的任务。
gulp.src('./app/script/*.coffee')
.pipe(plumber())
.pipe(coffee( bare: true ))
.pipe(gulp.dest('./public/js'))
相关插件的创建者在this article 上提供更多信息。
【讨论】:
感谢您的帮助。请参阅我的编辑。我想我正在做你所说的,但它仍然不起作用 您可能希望编辑您的答案以反映最终正确的做法,这样以后发现此问题的任何人都不必阅读评论链。 这一切都很好,但为什么我必须编写自己的错误处理程序?我使用 gulp 或 grunt 或任何预处理工具的全部原因是它为我做了肮脏的工作。我的代码中某处的语法错误(必然会发生)不应该使整个系统陷入停顿。将此与 Prepros(另一个预处理器)的 GUI 进行比较 - 该工具会准确地告诉您错误在哪里,并且在出现问题时不会挂起或退出。 令人惊讶的是,即使它是官方的 gulp 配方,也没有人提到 steam-combiner2!水管工也不错,但我总是更喜欢遵循 gulp 食谱,gulp 食谱由 gulp 保持最新,可以在github.com/gulpjs/gulp/tree/master/docs/recipes 查看 面对同样的难题,我决定在gulp.watch()
周围使用一个包装器,在 watch 函数的结果中添加一个 .on('error', function() this.emit('end') )
,因为它特别是我想要使其具有弹性的 watch 任务挂断。工作得非常好,失败的个别任务仍然打印自己的错误消息。见代码:github.com/specious/specious.github.io/commit/f8571d28【参考方案2】:
上面的例子对我不起作用。但是,以下是:
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']);
);
【讨论】:
这很好,但如果有错误通知也很好(目前这只是在终端中记录错误)【参考方案3】:使用一种格式的文件
(例如:仅限 *.coffee)
如果您只想使用一种格式的文件,那么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-plumber
和gulp-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;
);
附注:
这里用到的节点模块和函数:
// 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');
;
【讨论】:
我仍然看到这个 cmets 的改进。像速度比较,以及仅用于 .js 文件的链接(不包括缩小或 3d 方库,或来自 bower_components 的库)。但基本上它很容易调整和解决 Google.com 的这种嗅探【参考方案4】:我喜欢使用 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
【讨论】:
【参考方案5】:我已经实施了以下 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 测试。
【讨论】:
【参考方案6】:对此的简单解决方案是将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 编写的。与其他解决方案相比,它需要更少的代码,并且更容易记住和实施。 您能否将它的 bash 和您对此的其他想法编辑为您的答案?我不同意它比管道工更容易,但它是一种有效的(如果不是跨平台的)方法。我最初投了反对票,因为它甚至不清楚它是什么语言,除非你编辑答案,否则我不能改变我的投票。 所以您更喜欢让流崩溃并重新启动整个过程,这可能需要相当长的时间,具体取决于您使用无限循环执行的操作,而不是简单地捕获错误?对我来说似乎有点不安。说到更少的代码,它需要你 16 个字符来为你的任务添加管道工,而你的解决方案需要 36 个字符而不计算gulp watch
。
感谢@GeorgeMauer 的反馈,我进行了编辑并写了它工作的环境/平台。【参考方案7】:
打字稿
这对我有用。我使用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');
完全有效。
希望对您有所帮助。祝你好运。
【讨论】:
【参考方案8】:这对我有用->
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('错误', console.error.bind(console)) 行,但我必须运行 吞咽 命令作为根。我在一个 php 应用程序上运行 node gulp,所以我在一台服务器上有多个帐户,这就是为什么我遇到 gulp 打破语法错误的问题,因为我没有以 root 身份运行 gulp ...也许管道工和一些如果我以 root 身份运行,这里的其他答案会对我有用。 归功于 Accio Code https://www.youtube.com/watch?v=iMR7hq4ABOw 的答案。他说,通过处理错误,它可以帮助您确定错误在哪一行以及它在控制台中是什么,而且还可以阻止 gulp 因语法错误而中断。他说这是一种轻量级的修复,所以不确定它是否适用于您正在寻找的东西。不过快速修复,值得一试。希望这对某人有帮助!
【讨论】:
以上是关于防止错误破坏/崩溃 gulp watch的主要内容,如果未能解决你的问题,请参考以下文章
忽略或防止 ESLint 错误破坏 React 项目中的构建 (create-react-project)
Nodemon 与 gulp watch 绑定时崩溃并重新启动两次以上