410

in the snippet like this:

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"

In develop task I want to run clean and after it's done, run coffee and when that's done, run something else. But I can't figure that out. This piece doesn't work. Please advise.

Jacob
  • 77,566
  • 24
  • 149
  • 228
iLemming
  • 34,477
  • 60
  • 195
  • 309
  • 10
    The run-sequence npm module fixes this problem now - all other answers are now irrelevant - see OverZealous's answer below – danday74 Dec 13 '15 at 15:39
  • 1
    Gulp 4.0 natively supports running tasks in sequence, rendering `run-sequence` obsolete - see massanishi's answer below – Forivin Jan 12 '17 at 09:36
  • Gulp4 breaks more things than it fixes, it would seem. After battling with it for a few hours, I am back to 3.9.1. I realize major versions can/will break backcompat but with cryptic and useless error messages, i say no thanks. v4 is not ready. – Sat Thiru Dec 18 '18 at 22:14

15 Answers15

415

By default, gulp runs tasks simultaneously, unless they have explicit dependencies. This isn't very useful for tasks like clean, where you don't want to depend, but you need them to run before everything else.

I wrote the run-sequence plugin specifically to fix this issue with gulp. After you install it, use it like this:

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

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

You can read the full instructions on the package README — it also supports running some sets of tasks simultaneously.

Please note, this will be (effectively) fixed in the next major release of gulp, as they are completely eliminating the automatic dependency ordering, and providing tools similar to run-sequence to allow you to manually specify run order how you want.

However, that is a major breaking change, so there's no reason to wait when you can use run-sequence today.

OverZealous
  • 39,252
  • 15
  • 98
  • 100
  • 2
    @OverZealous thanks for the plugin! Btw, the `gulp-clean` plugin wasn't implementing Streams 2, so it had issues being run as a dependencies. This has been fixed as of release version 0.3.0, my co-worker submitted a PR to convert it over. – knownasilya Jun 10 '14 at 13:12
  • You don't need a plugin for this, Gulp has a built in syntax for task dependencies! – Indolering Mar 11 '15 at 22:32
  • 3
    @Indolering The built-in task dependency functionality does _not_ solve this scenario. Dependent tasks are always run: there's no built in way to run two tasks in a row _some_ of the time, but not _every_ time. `run-sequence` solves a critical piece of missing functionality in gulp. – OverZealous Mar 12 '15 at 02:27
  • I don't think that's what the OP was asking for. However, 4.0 does have an "after" feature for tasks. – Indolering Mar 12 '15 at 02:52
  • You should call the callback from `gulp.task` after the `console.log`, this tells gulp when the tasks are finished - otherwise it finishes early. – peterjwest Jun 30 '15 at 13:59
  • 2
    Also, task dependencies are not a complete solution. Say I have two gulp tasks that independently run tests using the database. Neither is dependent on the other, but I don't want either of them to run at the same time because they both need to use the database. – peterjwest Jun 30 '15 at 14:03
  • How do I use it with gulpIf? Can I do, something like ``` gulpIf(condition, runSequence('someTask')) ``` – InfinitePrime Dec 07 '15 at 10:02
  • 3
    Amazing module - Heres a great explanation of why it is needed - http://blog.mdnbar.com/gulp-for-simple-build-proccess - This should be the accepted answer – danday74 Dec 13 '15 at 15:42
  • it fails for me: https://gist.github.com/NinoSkopac/507ea6df303e4ec53d2b401d2f50f04b – The Onin Mar 25 '17 at 21:37
  • I found this article helpful regarding this same topic. https://davidwalsh.name/gulp-run-sequence – Ashok M A Mar 31 '17 at 15:00
  • But remember to place the tasks that you want to sync before the runSequence usage. Like in this answer, you will get error if clean and coffee tasks are not placed before develop. – Ashok M A Mar 31 '17 at 15:14
376

The only good solution to this problem can be found in the gulp documentation:

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']);
Mathieu Borderé
  • 4,357
  • 2
  • 16
  • 24
  • I think when I initially posted the question, that syntax wasn't yet available. I might be wrong though, maybe it was. – iLemming Oct 15 '14 at 20:06
  • Would be useful to have a link to the documentation – Oliver Tappin Nov 20 '14 at 09:09
  • 3
    The link to async docs are here, https://github.com/gulpjs/gulp/blob/master/docs/API.md#async-task-support – Richard Edwards Mar 11 '15 at 20:05
  • @Agzam, this should be the canonical answer, regardless of whether the syntax was available at the time. You selection of the other answer will lead newbs astray : ( – Indolering Mar 11 '15 at 22:34
  • 1
    It looks like in this example in the `default` task `one` will be executed two times. The first time in parallel with `two`, and the second time while executing `two`. – Warlock Apr 17 '15 at 05:59
  • Have you actually tested if that's the case ? – Mathieu Borderé Apr 17 '15 at 11:14
  • 6
    For some reason I'm getting `ReferenceError: err is not defined` trying to run this on a `gulp-compass` task, am I missing something? – waffl Jul 30 '15 at 22:13
  • 11
    @waffl this example uses a callback, which isn't the only way to do this. According to the [docs](https://github.com/gulpjs/gulp/blob/master/docs/API.md#return-a-stream), you can also "return a promise or stream that the engine should wait to resolve or end respectively." So if you return a stream in task one, e.g. `return gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');`, the key is to identify task one as a dependent when defining task two: `gulp.task('two', ['one'], function() {...` Task two will now wait for task one to end before running. – esvendsen Sep 02 '15 at 04:59
  • 24
    This creates a tight coupling between 'one' and 'two'. What if you want to run 'two' without running 'one' – wilk Dec 02 '15 at 21:36
  • 5
    you define a new task without the dependency ? – Mathieu Borderé Dec 02 '15 at 21:38
  • There are two topic related to this thread 1) GULP 4.0 will support running in sequence out of the box, thus the plugin will not be needed at all. 2) Sometimes you need to stop one of task which is run in sequence ie karma. There is good description how it should be done: http://dev.topheman.com/gulp-fail-run-sequence-with-a-correct-exit-code/ – przemcio Feb 05 '16 at 12:50
  • 8
    Needing two tasks to run sequentially implies a tight coupling. – Ringo Aug 31 '16 at 22:55
  • I have executed task2, which should execute dependent task1 and then execute task2, but it only execute task1, what should be the reason for this behavior? – Bandara Sep 28 '16 at 05:01
  • this way doe not work when executed task from node.js. Callback is not being called. – Paresh Thakor Oct 24 '16 at 11:15
  • 1
    Is it really necessary to specify task one as a dependency of the default task when it's already specified as a dependency of task two? Seems oddly redundant. – Drazen Bjelovuk Jan 08 '17 at 23:14
  • Worth highlighting that you should include ['one'] in `two`'s task definition otherwise they don't run sequentially. I love the silly design pattern discussion here about a few gulp tasks - it's just some tooling for build scripts not a billion dollar trading system! – Chris S Feb 27 '17 at 10:49
  • 1
    @DrazenBjelovuk -- I agree with you; isn't that what they meant in the comment "// alternatively: gulp.task('default', ['two']);" – Nate Anderson Mar 30 '17 at 15:47
135

It's not an official release yet, but the coming up Gulp 4.0 lets you easily do synchronous tasks with gulp.series. You can simply do it like this:

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

I found a good blog post introducing how to upgrade and make a use of those neat features: migrating to gulp 4 by example

massanishi
  • 2,044
  • 1
  • 15
  • 9
  • 3
    Method of choice for all newcomers. They should really start with gulp 4, skipping all 3.* hassle and wide range of antipatterns. – metalim Apr 06 '16 at 21:51
  • 1
    It's not limited to synchronous tasks. You can find the API docs for 4.0 [here](https://github.com/gulpjs/gulp/blob/4.0/docs/API.md#gulpseriestasks). To install gulp 4, run `npm install gulp@next` as suggested [here](https://github.com/gulpjs/gulp/issues/1486), until [these](https://github.com/gulpjs/gulp/issues/1604) issues are resolved. – Forivin Jan 12 '17 at 09:44
  • 193
    its 2017 and they still did not introduce it. Great. – Tomasz Mularczyk Jan 12 '17 at 19:53
  • According to their gitHub the only thing holding back the release is Vinly File System, so if your build pipeline doesn't require that you should just update to gulp@next – Chunky Chunk Jan 17 '17 at 10:29
  • 14
    I don't see the point, really. If you absolutely need A to run only after B runs, then A depends on B. Why can't you just specify that B is a dependency of A? `gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);` – musicin3d Mar 14 '17 at 17:59
  • 1
    @musicin3d if you need to execute more than one task before another one what you say won't work since tasks defined on the `deps` parameter run in parallel: https://github.com/gulpjs/gulp/blob/master/docs/API.md#deps – AxeEffect May 15 '17 at 14:19
  • @AxeEffect It does work though. "Both" will execute before "another." Even if they run in parallel, the requirement is satisfied. Now, if Both_A and Both_B need to run in serial, that implies that one of them depends on the other; it should be defined as a dependency. Example: Another => Both_A => Both_B. Therefore, Both_B executes first, then Both_A, then Another. Bam! Serial execution. No plugins. And your code accurately reflects the relationships among your tasks. – musicin3d May 16 '17 at 19:11
  • @musicin3d If you need C after B after A you'll need `run-sequence` or `gulp.series`. – AxeEffect May 16 '17 at 22:28
  • @AxeEffect But in fact, you don't. Try it how I explained. It works. Simply reasserting you have to do something a different way does not make it so. – musicin3d May 17 '17 at 16:33
  • 3
    @musicin3d What you say works, but you're coupling one task necessarily to the previous. For example, I want to be able to build without always having to lint before. It's a better solution to have independent tasks and decide the order of execution with an external tool. – AxeEffect May 17 '17 at 16:52
  • 1
    @AxeEffect Thank you! I just deleted my original reply because I realized this depends on what you define as a "dependency." :) *IF* there is a legitimate case to execute A without B, then A does not depend on B. There may be precedence, but NOT dependence. Task A doesn't care about B. If C depends on both A and B then C bears the responsibility of specifying that precedence (since there is no other mechanism to do so, and I can't even imagine what that would be anyway). There's probably a better example than "build and lint" out there, but I see what you mean now. Thanks for discussing this! – musicin3d May 17 '17 at 20:01
  • 1
    It's 2018 and 4.0 is still not officially released. – Jelle den Burger Aug 10 '18 at 07:46
  • When using `gulp.series`, make sure to signal async completion properly, or the second task will start running before the first task finishes. See https://gulpjs.com/docs/en/getting-started/async-completion – Joseph238 Jul 10 '20 at 16:21
  • i am getting error: AssertionError: Task never defined: clean, where clean is a default task of gulp. – sarbashis Jan 03 '22 at 16:43
56

I generated a node/gulp app using the generator-gulp-webapp Yeoman generator. It handled the "clean conundrum" this way (translating to the original tasks mentioned in the question):

gulp.task('develop', ['clean'], function () {
  gulp.start('coffee');
});
Henrik Aasted Sørensen
  • 6,966
  • 11
  • 51
  • 60
Steve
  • 597
  • 4
  • 3
  • 2
    This was the exact (and very simple) I needed. It addresses the scenario where I need to do something like a clean as a preceding dependency to build dependencies without setting clean as a dependency to those tasks. PS: Info about the gulp.start() bit - caveat emptor: https://github.com/gulpjs/gulp/issues/426 – Jaans Apr 29 '15 at 14:07
  • That makes sense; a callback after the main task (and it's dependent tasks) have completed. Thanks. – markau Apr 21 '16 at 00:16
  • 4
    If someone is wondering why there is no official documentation for `gulp.start()`, this answer from gulp member explains that: `gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it` (source: https://github.com/gulpjs/gulp/issues/426#issuecomment-41208007) – thybzi Aug 07 '16 at 19:29
  • 1
    In this case, how can I detect that `coffee` task is finished? If I don't detect it, `develop` task will finish earlier than `coffee` – thybzi Aug 07 '16 at 20:42
  • already got the answer from `run-sequence` source code: `gulp.on('task_stop')`. See my extended answer for details: http://stackoverflow.com/a/38818657/3027390 – thybzi Aug 07 '16 at 21:27
  • Thanks! My solution because simple and not additional things needed. – StrongLucky Jul 10 '18 at 23:35
  • `TypeError: gulp.start is not a function` – Jonathan Jun 06 '19 at 18:52
31

run-sequence is the most clear way (at least until Gulp 4.0 is released)

With run-sequence, your task will look like this:

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

But if you (for some reason) prefer not using it, gulp.start method will help:

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

Note: If you only start task without listening to result, develop task will finish earlier than coffee, and that may be confusing.

You may also remove event listener when not needed

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');
});

Consider there is also task_err event you may want to listen to. task_stop is triggered on successful finish, while task_err appears when there is some error.

You may also wonder why there is no official documentation for gulp.start(). This answer from gulp member explains the things:

gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it

(source: https://github.com/gulpjs/gulp/issues/426#issuecomment-41208007)

thybzi
  • 1,223
  • 13
  • 15
26

According to the Gulp docs:

Are your tasks running before the dependencies are complete? Make sure your dependency tasks are correctly using the async run hints: take in a callback or return a promise or event stream.

To run your sequence of tasks synchronously:

  1. Return the event stream (e.g. gulp.src) to gulp.task to inform the task of when the stream ends.
  2. Declare task dependencies in the second argument of gulp.task.

See the revised code:

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"
senornestor
  • 4,075
  • 2
  • 33
  • 33
10

I was having this exact same problem and the solution turned out to be pretty easy for me. Basically change your code to the following and it should work. NOTE: the return before gulp.src made all the difference for me.

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"
CPP
  • 1,031
  • 3
  • 10
  • 26
  • Thanks for the note on returning! Was going nuts trying to figure out why gulp was src-ing tasks out of order. – Andrew F Jul 12 '15 at 21:47
  • This should be the correct answer to avoid tight coupling between tasks. Works well. gulp.series available in 4.0 is probably the best answer, but as of today, 4.0 is not available. – wilk Dec 02 '15 at 21:40
  • gulp develop will run clean or coffee first – scape Oct 05 '17 at 15:35
9

tried all proposed solutions, all seem to have issues of their own.

If you actually look into the Orchestrator source, particularly the .start() implementation you will see that if the last parameter is a function it will treat it as a callback.

I wrote this snippet for my own tasks:

  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" ));
Assaf Moldavsky
  • 1,681
  • 1
  • 19
  • 30
4

I was searching for this answer for a while. Now I got it in the official gulp documentation.

If you want to perform a gulp task when the last one is complete, you have to return a stream:

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));
});
4

For me it was not running the minify task after concatenation as it expects concatenated input and it was not generated some times.

I tried adding to a default task in execution order and it didn't worked. It worked after adding just a return for each tasks and getting the minification inside gulp.start() like below.

/**
* 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']); 

Source http://schickling.me/synchronous-tasks-gulp/

Anshad Vattapoyil
  • 23,145
  • 18
  • 84
  • 132
3

Simply make coffee depend on clean, and develop depend on coffee:

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

Dispatch is now serial: cleancoffeedevelop. Note that clean's implementation and coffee's implementation must accept a callback, "so the engine knows when it'll be done":

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

In conclusion, below is a simple gulp pattern for a synchronous clean followed by asynchronous build dependencies:

//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 is smart enough to run clean exactly once per build, no matter how many of build's dependencies depend on clean. As written above, clean is a synchronization barrier, then all of build's dependencies run in parallel, then build runs.

akarve
  • 1,214
  • 10
  • 11
3

Gulp and Node use promises.

So you can do this:

// ... 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();
    });
  });
});

If you return the gulp stream, you can use the then() method to add a callback. Alternately, you can use Node's native Promise to create your own promises. Here I use Promise.all() to have one callback that fires when all the promises resolve.

Peter J. Hart
  • 367
  • 2
  • 7
1

To wait and see if the task is finished and then the rest, I have it this way:

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

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

Julian
  • 598
  • 8
  • 23
1

The very simple and efficient solution that I found out to perform tasks one after the other(when one task gets completed then second task will be initiated) (providing just an example) is :
gulp.task('watch', () =>
gulp.watch(['src/**/*.css', 'src/**/*.pcss'], gulp.series('build',['copy'])) );
This means when you need to run the first-task before second-task, you need to write the second task(copy in this case) in square brackets.
NOTE
There should be round parenthesis externally for the tasks(until you want them to occur simultaneously)

Ayush Shankar
  • 307
  • 2
  • 9
-8

Try this hack :-) Gulp v3.x Hack for Async bug

I tried all of the "official" ways in the Readme, they didn't work for me but this did. You can also upgrade to gulp 4.x but I highly recommend you don't, it breaks so much stuff. You could use a real js promise, but hey, this is quick, dirty, simple :-) Essentially you use:

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

Check out the post!