【问题标题】:Gulp watch terminates or builds the whole task chainGulp watch 终止或构建整个任务链
【发布时间】:2016-10-03 02:07:35
【问题描述】:

我正在开发一个带有以下构建步骤的打字稿项目:

  • 皮棉
  • 构建
  • 测试

我使用 Gulp 4.0 作为构建工具,并希望有一个 watch 任务,它应该触发测试(这意味着 lint 和构建任务是先触发的)。目前,当发生错误(例如 lint 错误)时,watch 任务终止。

这个问题众所周知并且很容易解决。典型的解决方案是 a) 防止错误或 b) 修补管道行为。

a) 对于gulp-tslint,我可以使用他们主页上的这个配置:

gulp.task("invalid-noemit", () =>
    gulp.src("input.ts")
        .pipe(tslint())
        .pipe(tslint.report("prose", {
          emitError: false
        }))
);

但是当我包含 emitError 标志时,会记录 lint 错误并执行所有后续 gulp 任务(构建、测试)。

b) 我也可以使用gulp-plumber 或手动捕获错误(请参阅here),但所有这些已知解决方案的行为都是相同的,执行以下 gulp 任务(构建、测试)。

我想要的是任务链在错误后停止(在 lint 错误后没有构建和测试),但 watch 任务永远不应该停止。我怎么能解决这个问题?观察者任务如下所示:

// watcher
gulp.task('watch', gulp.series('test', function doWatch() {
    gulp.watch([
        config.paths.sourcePattern,
        config.paths.testPattern,
        'gulpfile.js'
    ], gulp.parallel('test'));
}));

你可以找到完整的gulpfile.jshere

【问题讨论】:

  • 你能发布你的监视任务吗?
  • 我用监视任务更新了问题。
  • 如果你在 watch 任务上使用 gulp.series('lint', 'build', 'test') ,而不是直接依赖其他人,是不是也一样?

标签: typescript gulp watch


【解决方案1】:

您的手表停止的原因是因为err 对象在回调链中向上传播。您必须阻止 err 到达最终的 gulp.watch() 回调。

您可以通过包装 gulp.watch() 提供的回调来做到这一点,并且永远不要将 err 对象传递给原始回调:

gulp.task('watch', function() {
  gulp.watch([
      config.paths.sourcePattern,
      config.paths.testPattern,
      'gulpfile.js'
    ], {ignoreInitial:false}, function(cb) {
      gulp.series('lint', 'build', 'test')(function wrappedCb(err) {
        cb(); // not passing err here
    });
  });
});

请注意,gulp.series('lint', 'build', 'test') 实际上并不执行任务。它只返回一个接受回调的新函数。只有当这个新函数以gulp.series('lint', 'build', 'test')() 调用时,才会真正执行任务。

我还添加了ignoreInitial 选项,以便手表在启动后执行一次,这似乎是您在watch 任务中尝试使用gulp.series('test', ...) 实现的目标。

(除此之外:观看gulpfile.js 是没用的。在您重新运行gulp watch 之前,对gulpfile 的更改不会生效。没有办法解决这个问题。)


最后你需要解耦你的其他任务,所以它们对其他任务没有明确的依赖关系。像这样翻译 gulp 3.x 任务很诱人:

gulp.task('foo', ['bar'], function() { });

像这样进入 gulp 4.x 任务:

gulp.task('foo', gulp.series('bar', function() { }));

它们在表面上看起来很相似,但在引擎盖下却完全不同。有关该主题的更多信息,请参阅this article

一个好的策略是将您的任务分为两类:

  1. 独立任务,只做一件事,不依赖于其他任务。
  2. 复合任务以串行或并行方式运行多个其他任务。

按照这个原则,您的其他任务可以重构为:

gulp.task('lint', function() {
  return gulp.src([
    config.paths.sourcePattern,
    config.paths.testPattern
  ])
  .pipe(tslint())
  .pipe(tslint.report('verbose', {
    emitError: true, // we WANT to emit this err so our other tasks don't run
    summarizeFailureOutput: true
  }));
});

gulp.task('build-app', function doBuildApp() {
  /* ... */
});

gulp.task('build-test', function doBuildTest() {
  /* ... */
});

gulp.task('build', gulp.series('lint', 'build-app', 'build-test'));

gulp.task('test', gulp.series(function doPreTest() {
    /* ... */
  }, function doTest() {
    /* ... */
  }, function doPostTest() {
    /* ... */
}));

【讨论】:

  • 我知道如何防止 watch 任务停止,问题是如何防止在发生 lint 错误时执行构建和测试(或在发生构建错误时执行测试)。
  • 您真的尝试过我的解决方案吗?因为它正是这样做的。 lint 任务发出一个err 对象,它阻止buildtest 运行。但是err 没有传递给cb,这意味着手表不会停止。
  • 我已经尝试过您的解决方案。唯一的区别是我在这个系列中没有 lint、build 和 test,因为 lint 是 build 的先决条件,而 build 是 test 的先决条件。因此,我只在该系列中进行了测试,这导致了所有步骤的执行。顺便说一句,为什么gulp.series()() 工作,你能解释一下吗?
  • 我添加了指向完整 gulpfile 的链接。
  • 更新了我的答案。我在你的 gulpfile.js 中找不到任何说 buildtest 的先决条件的东西,所以我不知道为什么当你只运行 test 时应该运行所有三个任务。
猜你喜欢
  • 2015-03-11
  • 2015-07-14
  • 2018-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多