【问题标题】:How to run Gulp tasks sequentially one after the other如何一个接一个地依次运行 Gulp 任务
【发布时间】:2014-05-14 12:13:12
【问题描述】:

在sn-p中是这样的:

gulp.task "coffee", ->
    gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean",->
    gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"

develop 任务中,我想运行clean,完成后,运行coffee,完成后,运行其他内容。但我无法弄清楚。这块不行。请指教。

【问题讨论】:

  • run-sequence npm 模块现在修复了这个问题 - 所有其他答案现在都无关紧要 - 请参阅下面的 OverZealous 的答案
  • Gulp 4.0 原生支持按顺序运行任务,使run-sequence 过时 - 请参阅下面的massanishi 答案
  • Gulp4 破坏的东西比它修复的要多,看起来。在与它战斗了几个小时后,我又回到了 3.9.1。我意识到主要版本可以/将会破坏 backcompat 但带有神秘和无用的错误消息,我说不,谢谢。 v4 尚未准备好。

标签: javascript node.js coffeescript gulp


【解决方案1】:

默认情况下,gulp 会同时运行任务,除非它们有明确的依赖关系。这对于像 clean 这样的任务不是很有用,您不想依赖这些任务,但您需要它们在其他所有事情之前运行。

我写了the run-sequence plugin 专门用 gulp 解决这个问题。安装后,像这样使用它:

var runSequence = require('run-sequence');

gulp.task('develop', function(done) {
    runSequence('clean', 'coffee', function() {
        console.log('Run something else');
        done();
    });
});

您可以阅读软件包 README 中的完整说明——它还支持同时运行一些任务集。

请注意,这将是 (effectively) fixed in the next major release of gulp,因为它们完全消除了自动依赖排序,并提供类似于 run-sequence 的工具,允许您手动指定所需的运行顺序。

但是,这是一个重大的重大变化,所以没有理由等待您今天可以使用 run-sequence

【讨论】:

  • @OverZealous 感谢插件!顺便说一句,gulp-clean 插件没有实现 Streams 2,因此它在作为依赖项运行时存在问题。从 0.3.0 版开始,此问题已得到修复,我的同事提交了 PR 将其转换过来。
  • 你不需要插件,Gulp 有一个内置的任务依赖语法!
  • @Indolering 内置的任务依赖功能不能解决这种情况。相关任务始终运行:没有内置方法可以在某些时间连续运行两个任务,但不是每次时间。 run-sequence 解决了 gulp 中缺少的一个关键功能。
  • 另外,任务依赖并不是一个完整的解决方案。假设我有两个使用数据库独立运行测试的 gulp 任务。两者都不依赖于另一个,但我不希望它们中的任何一个同时运行,因为它们都需要使用数据库。
  • 惊人的模块 - 这里很好地解释了为什么需要它 - blog.mdnbar.com/gulp-for-simple-build-proccess - 这应该是公认的答案
【解决方案2】:

在 gulp 文档中可以找到解决这个问题的唯一好方法:

var gulp = require('gulp');

// takes in a callback so the engine knows when it'll be done
gulp.task('one', function(cb) {
  // do stuff -- async or otherwise
  cb(err); // if err is not null and not undefined, the orchestration will stop, and 'two' will not run
});

// identifies a dependent task must be complete before this one begins
gulp.task('two', ['one'], function() {
  // task 'one' is done now
});

gulp.task('default', ['one', 'two']);
// alternatively: gulp.task('default', ['two']);

【讨论】:

  • 由于某种原因,我收到 ReferenceError: err is not defined 试图在 gulp-compass 任务上运行它,我错过了什么吗?
  • @waffl 这个例子使用回调,这不是唯一的方法。根据docs,您还可以“返回引擎应分别等待解析或结束的承诺或流”。因此,如果您在任务一中返回一个流,例如return gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');,关键是在定义任务二时将任务一识别为依赖:gulp.task('two', ['one'], function() {...任务二现在将等待任务一结束后再运行。
  • 这会在“一”和“二”之间建立紧密耦合。如果您想运行“二”而不运行“一”怎么办
  • 你定义了一个没有依赖的新任务?
  • 需要两个任务顺序运行意味着紧密耦合。
【解决方案3】:

它还不是正式版本,但即将推出的 Gulp 4.0 让您可以轻松地使用 gulp.series 执行同步任务。你可以这样做:

gulp.task('develop', gulp.series('clean', 'coffee'))

我找到了一篇很好的博客文章,介绍了如何升级和使用这些简洁的功能: migrating to gulp 4 by example

【讨论】:

  • 所有新手的首选方法。他们真的应该从 gulp 4 开始,跳过所有 3.* 的麻烦和广泛的反模式。
  • 它是 2017 年,他们仍然没有介绍它。太好了。
  • 我不明白这一点,真的。如果您绝对需要 A 仅在 B 运行后运行,那么 A 依赖于 B。为什么不能只指定 B 是 A 的依赖项? gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);
  • @musicin3d 你说的很管用,但你必须将一项任务与前一项联系起来。例如,我希望能够构建而不必总是使用 lint。拥有独立任务并使用外部工具决定执行顺序是更好的解决方案。
  • 2018 年,他们终于推出了它。太好了。
【解决方案4】:

我使用generator-gulp-webapp Yeoman 生成器生成了一个节点/gulp 应用程序。它以这种方式处理“干净的难题”(转换为问题中提到的原始任务):

gulp.task('develop', ['clean'], function () {
  gulp.start('coffee');
});

【讨论】:

  • 这正是我所需要的(而且非常简单)。它解决了我需要在不将 clean 设置为这些任务的依赖项的情况下,将 clean 作为前面的依赖项来构建依赖项的场景。 PS:有关 gulp.start() 位的信息 - 警告购买者:github.com/gulpjs/gulp/issues/426
  • 有道理;主要任务(及其相关任务)完成后的回调。谢谢。
  • 如果有人想知道为什么没有gulp.start() 的官方文档,gulp 成员的回答解释说:gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it(来源:github.com/gulpjs/gulp/issues/426#issuecomment-41208007
  • 在这种情况下,如何检测到coffee 任务已完成?如果我没有检测到它,develop 任务将比coffee 更早完成
  • 已经从run-sequence源代码:gulp.on('task_stop')得到答案。有关详细信息,请参阅我的扩展答案:stackoverflow.com/a/38818657/3027390
【解决方案5】:

run-sequence 是最清晰的方式(至少在 Gulp 4.0 发布之前)

使用运行序列,您的任务将如下所示:

var sequence = require('run-sequence');
/* ... */
gulp.task('develop', function (done) {
    sequence('clean', 'coffee', done);
});

但如果你(出于某种原因)不想使用它,gulp.start 方法会有所帮助

gulp.task('develop', ['clean'], function (done) {
    gulp.on('task_stop', function (event) {
        if (event.task === 'coffee') {
            done();
        }
    });
    gulp.start('coffee');
});

注意: 如果你只开始任务而不听结果,develop 任务将比coffee 早完成,这可能会造成混淆。

您也可以在不需要时移除事件监听器

gulp.task('develop', ['clean'], function (done) {
    function onFinish(event) {
        if (event.task === 'coffee') {
            gulp.removeListener('task_stop', onFinish);
            done();
        }
    }
    gulp.on('task_stop', onFinish);
    gulp.start('coffee');
});

考虑还有task_err 事件你可能想听。 task_stop在成功完成时触发,而task_err在出现错误时出现。

您可能还想知道为什么没有gulp.start() 的官方文档。 gulp 成员的这个答案解释了事情:

gulp.start 故意没有记录,因为它会导致复杂的构建文件,我们不希望人们使用它

(来源:https://github.com/gulpjs/gulp/issues/426#issuecomment-41208007

【讨论】:

  • 给这个人两杯咖啡!删除监听器的解决方案非常完美!
  • 这确实是答案,或者只是“gulp 4”。运行顺序稳健。
【解决方案6】:

根据 Gulp 文档:

您的任务是否在依赖项完成之前运行?确保您的依赖任务正确使用异步运行提示:接受回调或返回承诺或事件流。

同步运行您的任务序列:

  1. 将事件流(如gulp.src)返回给gulp.task通知 流何时结束的任务。
  2. gulp.task的第二个参数中声明任务依赖。

查看修改后的代码:

gulp.task "coffee", ->
    return gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean", ['coffee'], ->
      return gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"

【讨论】:

  • 这应该是正确的答案!返回任务成功了!谢谢大佬。
【解决方案7】:

我遇到了同样的问题,结果对我来说解决方案非常简单。基本上将您的代码更改为以下内容,它应该可以工作。注意:gulp.src 之前的返回对我来说意义重大。

gulp.task "coffee", ->
    return gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean",->
    return gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"

【讨论】:

  • 感谢您的退货说明!想弄清楚为什么 gulp 会乱序执行任务。
  • 这应该是避免任务之间紧密耦合的正确答案。效果很好。 4.0 中可用的 gulp.series 可能是最好的答案,但截至今天,4.0 不可用。
  • gulp develop 将先运行干净或咖啡
【解决方案8】:

尝试了所有建议的解决方案,似乎都有自己的问题。

如果您真正查看 Orchestrator 源代码,尤其是 .start() 实现,您会发现如果最后一个参数是一个函数,它会将其视为回调。

我为自己的任务编写了这个 sn-p:

  gulp.task( 'task1', () => console.log(a) )
  gulp.task( 'task2', () => console.log(a) )
  gulp.task( 'task3', () => console.log(a) )
  gulp.task( 'task4', () => console.log(a) )
  gulp.task( 'task5', () => console.log(a) )

  function runSequential( tasks ) {
    if( !tasks || tasks.length <= 0 ) return;

    const task = tasks[0];
    gulp.start( task, () => {
        console.log( `${task} finished` );
        runSequential( tasks.slice(1) );
    } );
  }
  gulp.task( "run-all", () => runSequential([ "task1", "task2", "task3", "task4", "task5" ));

【讨论】:

    【解决方案9】:

    我一直在寻找这个答案。现在我在官方 gulp 文档中得到了它。

    如果你想在最后一个完成后执行 gulp 任务,你必须返回一个流:

    gulp.task('wiredep', ['dev-jade'], function () {
        var stream = gulp.src(paths.output + '*.html')
            .pipe($.wiredep())
            .pipe(gulp.dest(paths.output));
    
        return stream; // execute next task when this is completed
    });
    
    // First will execute and complete wiredep task
    gulp.task('prod-jade', ['wiredep'], function() {
        gulp.src(paths.output + '**/*.html')
            .pipe($.minifyHtml())
            .pipe(gulp.dest(paths.output));
    });

    【讨论】:

      【解决方案10】:

      只需让coffee 依赖于clean,而develop 依赖于coffee

      gulp.task('coffee', ['clean'], function(){...});
      gulp.task('develop', ['coffee'], function(){...});
      

      Dispatch 现在是串行的:cleancoffeedevelop。注意clean 的实现和coffee 的实现必须接受回调,"so the engine knows when it'll be done"

      gulp.task('clean', function(callback){
        del(['dist/*'], callback);
      });
      

      总之,下面是一个简单的 gulp 模式,用于同步 clean 后跟异步构建依赖项

      //build sub-tasks
      gulp.task('bar', ['clean'], function(){...});
      gulp.task('foo', ['clean'], function(){...});
      gulp.task('baz', ['clean'], function(){...});
      ...
      
      //main build task
      gulp.task('build', ['foo', 'baz', 'bar', ...], function(){...})
      

      Gulp 足够聪明,可以在每个 build 运行一次 clean,无论 build 的依赖项中有多少依赖于 clean。如上所述,clean 是一个同步屏障,那么build 的所有依赖项并行运行,然后build 运行。

      【讨论】:

        【解决方案11】:

        对我来说,它在连接后没有运行 minify 任务,因为它需要连接输入并且有时没有生成。

        我尝试按执行顺序添加到默认任务,但没有成功。在为每个任务添加一个return 并在gulp.start() 中进行缩小后,它就起作用了,如下所示。

        /**
        * Concatenate JavaScripts
        */
        gulp.task('concat-js', function(){
            return gulp.src([
                'js/jquery.js',
                'js/jquery-ui.js',
                'js/bootstrap.js',
                'js/jquery.onepage-scroll.js',
                'js/script.js'])
            .pipe(maps.init())
            .pipe(concat('ux.js'))
            .pipe(maps.write('./'))
            .pipe(gulp.dest('dist/js'));
        });
        
        /**
        * Minify JavaScript
        */
        gulp.task('minify-js', function(){
            return gulp.src('dist/js/ux.js')
            .pipe(uglify())
            .pipe(rename('ux.min.js'))
            .pipe(gulp.dest('dist/js'));
        });
        
        gulp.task('concat', ['concat-js'], function(){
           gulp.start('minify-js');
        });
        
        gulp.task('default',['concat']); 
        

        来源http://schickling.me/synchronous-tasks-gulp/

        【讨论】:

          【解决方案12】:

          Gulp 和 Node 使用 promises

          所以你可以这样做:

          // ... require gulp, del, etc
          
          function cleanTask() {
            return del('./dist/');
          }
          
          function bundleVendorsTask() {
            return gulp.src([...])
              .pipe(...)
              .pipe(gulp.dest('...'));
          }
          
          function bundleAppTask() {
            return gulp.src([...])
              .pipe(...)
              .pipe(gulp.dest('...'));
          }
          
          function tarTask() {
            return gulp.src([...])
              .pipe(...)
              .pipe(gulp.dest('...'));
          }
          
          gulp.task('deploy', function deployTask() {
            // 1. Run the clean task
            cleanTask().then(function () {
              // 2. Clean is complete. Now run two tasks in parallel
              Promise.all([
                bundleVendorsTask(),
                bundleAppTask()
              ]).then(function () {
                // 3. Two tasks are complete, now run the final task.
                tarTask();
              });
            });
          });
          

          如果返回 gulp 流,可以使用 then() 方法添加回调。或者,您可以使用 Node 的原生 Promise 创建自己的 Promise。在这里,我使用Promise.all() 来设置一个回调,当所有承诺都解决时触发。

          【讨论】:

            【解决方案13】:

            要等着看任务是否完成然后剩下的,我是这样处理的:

            gulp.task('default',
              gulp.series('set_env', gulp.parallel('build_scss', 'minify_js', 'minify_ts', 'minify_html', 'browser_sync_func', 'watch'),
                function () {
                }));
            

            荣誉:https://fettblog.eu/gulp-4-parallel-and-series/

            【讨论】:

              【解决方案14】:

              我发现一个接一个地执行任务的非常简单有效的解决方案(当一个任务完成时,将启动第二个任务)(仅提供一个示例)是:
              gulp.task('watch', () =&gt;
              gulp.watch(['src/**/*.css', 'src/**/*.pcss'], gulp.series('build',['copy'])) );
              这意味着当您需要在second-task 之前运行first-task 时,您需要在方括号中编写第二个任务(在这种情况下为copy)。
              注意
              任务外部应该有圆括号(直到您希望它们同时发生)

              【讨论】:

                【解决方案15】:

                试试这个技巧 :-) Gulp v3.x Hack for Async bug

                我尝试了自述文件中的所有“官方”方法,它们对我不起作用,但确实如此。您也可以升级到 gulp 4.x,但我强烈建议您不要升级,它会破坏很多东西。你可以使用真正的 js 承诺,但是,这很快,很脏,很简单 :-) 基本上你使用:

                var wait = 0; // flag to signal thread that task is done
                if(wait == 0) setTimeout(... // sleep and let nodejs schedule other threads
                

                查看帖子!

                【讨论】:

                • 有更好的方法来解决这个问题,使用 setTimeout 是不合适的。您无法确切知道完成一项任务需要多长时间。
                • 你真的应该在写任何代码之前三思而行
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-07-03
                • 2014-07-15
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多