如何依次依次运行Gulp任务


398

在如下代码段中:

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运行其他内容。但我无法弄清楚。这件作品不起作用。请指教。


10
运行序列npm模块现在解决了此问题-所有其他答案现在都不再相关-参见下面的
— OverZealous

1
Gulp 4.0本机支持按顺序运行任务,使之run-sequence过时-请参阅下面的massanishi的答案
— Forivin

Gulp4看起来比解决的要多。与它战斗了几个小时后,我回到了3.9.1。我意识到主要版本可以/将打破反向兼容,但带有隐秘和无用的错误消息,我说不,谢谢。v4尚未准备好。
— 星期六星期六

Answers:


121

它不是正式版本,但是即将推出的Gulp 4.0使您可以轻松地使用gulp.series进行同步任务。您可以像这样简单地做到这一点:

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

我找到了一篇不错的博客文章,其中介绍了如何升级和使用这些简洁功能: 通过示例迁移到gulp 4


3
所有新移民的选择方法。他们应该真正从gulp 4开始,跳过所有3. *麻烦和范围广泛的反模式。
— metalim 2016年

187
它的2017年,他们仍然没有推出。大。
— Tomasz Mularczyk

14
我不明白这一点,真的。如果您绝对需要A仅在B运行之后才能运行,那么A取决于B。为什么不能仅指定B是A的依赖项?gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);
— musicin3d

3
@ musicin3d您说的有效,但您必须将一项任务与上一项任务结合起来。例如,我希望能够构建而不必总是先掉毛。拥有独立的任务并使用外部工具确定执行顺序是一个更好的解决方案。
— AxeEffect

11
它的2018年,他们终于做了介绍。大。
— dargmuesli

411

默认情况下,gulp会同时运行任务,除非它们具有明确的依赖性。对于clean您不想依赖的任务(例如),这不是很有用,但您需要它们先运行。

我专门编写了run-sequence插件来解决gulp的问题。安装后,按以下方式使用它:

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

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

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

请注意,这将在gulp的下一个主要版本中(有效)修复,因为它们完全消除了自动依赖性排序,并提供了类似于run-sequence允许您手动指定运行顺序的工具。

但是,这是一个重大的重大变化,因此没有理由等到run-sequence今天就可以使用。


2
@OverZealous感谢您的插件!顺便说一句,该gulp-clean插件未实现Streams 2,因此它存在作为依赖项运行的问题。自版本0.3.0起已修复此问题,我的同事提交了一份PR以对其进行转换。
— 已知的2014年

3
@Indolering内置的任务相关的功能并没有解决这个问题的方案。依赖的任务总是运行:没有内置的方法可以在某些时间(但不是每次)连续运行两个任务。 run-sequence解决了在gulp中缺少功能的关键问题。
— OverZealous

2
此外,任务依赖性也不是完整的解决方案。假设我有两个gulp任务,它们分别使用数据库运行测试。两者都不依赖于另一个,但是我不希望它们同时运行,因为它们都需要使用数据库。
— peterjwest

3
令人惊叹的模块- 此处对为什么需要它的很好解释-blog.mdnbar.com/gulp-for-simple-build-proccess-这应该是公认的答案
— danday74,2013年

5
非常感谢您为此提出了解决方案,但是我们需要其他工具来获得顺序执行是荒谬的。顺序执行应该是默认的,或者至少很容易做到。Makefile已连续执行40年。JS生态系统让我感到恶心。73兆字节的node_modules只是用于编译没有任何功能的样板项目,并且仍然不包括顺序执行的功能。操作系统适合放在一个较小的空间中,并且具有内核和驱动程序FFS。
— joonas.fi,2017年

371

可以在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']);

6
由于某种原因,我ReferenceError: err is not defined试图在某个gulp-compass任务上运行它,我丢失了什么吗?
— waffl

11
@waffl本示例使用回调,这不是执行此操作的唯一方法。根据文档,您还可以“分别返回引擎应等待解决或结束的承诺或信息流”。因此,如果您在任务1中返回流,例如return gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');,关键是在定义任务2时将任务1标识为从属:gulp.task('two', ['one'], function() {... 任务2现在将等待任务1结束再运行。
— esvendsen

24
这在“一个”和“两个”之间建立了紧密的耦合。如果您想运行“两个”而不运行“一个”
— 怎么办

5
您定义没有依赖项的新任务?
— MathieuBorderé15年

8
需要依次执行两个任务意味着紧密耦合。
— 林戈

56

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

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

2
这正是我需要的(非常简单)。它解决了以下情况,即我需要做类似clean的操作来构建依赖关系,而无需将clean设置为对这些任务的依赖关系。PS:有关gulp.start()位的信息-警告免责
— 声明

这就说得通了; 主要任务(及其相关任务)完成后的回调。谢谢。
— markau '16

4
如果有人想知道为什么没有正式文档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(source:github.com/gulpjs/gulp/issues/426#issuecomment-41208007)
— thybzi

1
在这种情况下,如何检测到coffee任务已完成?如果我没有检测到,develop任务将早于coffee
— thybzi '16

已经从run-sequence源代码获得了答案:gulp.on('task_stop')。请参阅我的扩展答案以获取详细信息:stackoverflow.com/a/38818657/3027390
— thybzi '16

32

运行顺序是最清晰的方法(至少在Gulp 4.0发布之前)

使用run-sequence,您的任务将如下所示:

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)


给这个男人两杯咖啡!删除监听器的解决方案非常完美!
— daniel.bavrin

这确实是答案,或者仅仅是“ gulp 4”。运行顺序很稳定。
— LAdams87

26

根据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"

4
这应该是正确的答案!归还任务就成功了!谢啦。
— Dzoukr 2015年

10

我遇到了完全相同的问题,对我来说解决方案非常容易。基本上将您的代码更改为以下代码,它应该可以工作。注意: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不能按顺序保存任务,真是疯了。
— Andrew F

这应该是正确的答案,以避免任务之间的紧密联系。效果很好。gulp.series在4.0中可用可能是最好的答案,但是到目前为止,4.0尚不可用。
— 2015年

gulp开发将首先运行清洁或咖啡
— scape

8

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

如果您实际查看Orchestrator的源代码,尤其是.start()实现,您将看到,如果最后一个参数是一个函数,它将把它当作回调。

我为自己的任务编写了以下代码段:

  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" ));

4

我一直在寻找这个答案一段时间。现在,我在正式的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));
});


3

只需使coffee依赖clean,并develop依赖coffee:

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

派遣是现在串口:clean→交通coffee→交通develop。请注意,clean的实现和coffee的实现必须接受回调,“以便引擎知道何时完成”:

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足够聪明,可以clean每次精确地运行一次build,无论build依赖于多少依赖项clean。如上所述,它clean是一个同步屏障,然后所有build依赖项并行运行,然后build运行。


3

对我来说,它没有在连接后运行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/


2

Gulp和Node使用承诺。

因此,您可以执行以下操作:

// ... 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()一个回调,当所有promise都解决时触发该回调。


-8

试试这个技巧:-) 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。您无法确切地知道任务将花费多少时间。
— Reginaldo Camargo Ribeiro'9

在编写任何代码pff之前,您真的应该考虑一下
— DDD
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.