5

I'm having some trouble with a couple of gulp tasks. i've tried everything and followed the documentation but nothing seems to work. Hoping someone can help.

What i'm trying to do is have sass minification happen, then rsync the result to a local vagrant folder (NOT a remote server), then reload browser sync.

The problem i am having is that I'm fighting the fact that gulp wants to run all the tasks together. I need them to happen one after the other. All the tasks work on their own, i am just having trouble making them run sequentially. I've tried callbacks and playing with dependency but i'm obviously missing something.

My setup is complicated, all my tasks are in separate js files but i've tried to combine what i have into this single github gist so people can help. Thanks for any assistance.

https://gist.github.com/CodeStalker/9661725dcaf105d2ed6c

The only way I have got this to work is to pipe rsync onto the end of the sass magnification, and wrap it in gulp-if using a server: true variable so it only does the rsync if it knows its running on a VM. Not ideal.

2 Answers2

3

This is a common issue people run into with Gulp, especially when coming from Grunt. Gulp is async to the max, it always wants to do as many things as it can all at the same time.

The first step to getting tasks to run sequentially is to let gulp know when your task ends, this can be done a couple different ways.

1) Return a stream, gulp will wait for the stream's "end" event as the trigger for that task being done. Example:

gulp.task( "stream-task", function(){
  return gulp.src( srcGlob )
    .pipe(sass())
    .pipe(compressCSS())
    .pipe(gulp.dest( destGlob ));
});

2) Return a Promise, gulp will wait for the promise to enter a resolved state before signaling the task as done. Example: (not perfect just to get the point across)

gulp.task( "promise-task", function() {
  return new Promise(function(resolve, reject){
    fs.readFile( "filename", function( err, data ){
      if( err ){ return reject(err); }
      return resolve( data );
    });
  });
});

3) Call the task callback, if the function doesn't return anything but the function signature takes an argument, that argument will be a callback function you can call to signal the task as done. Example:

gulp.task( "cb-task", function( done ){
  fs.readFile( "filename", function( err, data ){
    // do stuff, call done...
    done();
  });
});

Most often you are going to be returning a stream like example 1, which is what a typical gulp task looks like. Options 2 and 3 are more for when you are doing something that isn't really a traditional stream based gulp task.

The next thing is setting the "dependency" of one task for another. The gulp docs show this as the way you do that:

gulp.task( "some-task-with-deps", [ "array-of-dep", "task-names" ], function(){ /* task body */ });

Now I don't know the current status but there were some issues with these dependency tasks not running in the proper order. This was originally caused by a problem with one of gulp's dependencies (orchestrator I believe). One kind gentleman out there in NPM land made a nice little package to be used in the interim while the bugs were being worked out. I started using it to order my tasks and haven't looked back.

https://www.npmjs.com/package/run-sequence

The documentation is good so I won't go into a lot of detail here. Basically run-sequence lets explicitly order your gulp tasks, just remember it doesn't work if you don't implement one of the three options above for each of your tasks.

Looking at your gist adding a couple missing return statements in your tasks may just do the trick, but as an example this is what my "dev" task looks like for my project at work...

gulp.task( "dev", function( done ){
  runSequence(
    "build:dev",
    "build:tests",
    "server:dev",
    [
      "less:watch",
      "jscs:watch",
      "lint:watch",
      "traceur:watch"
    ],
    "jscs:dev",
    "lint:dev",
    "tdd",
    done // <-- thats the callback method to gulp let know when this task ends
  );
});

Also for reference my "build:dev" task is another use of run-sequence

gulp.task( "build:dev", function( done ){
  runSequence(
    "clean:dev",
    [
      "less:dev",
      "symlink:dev",
      "vendor:dev",
      "traceur:dev"
    ],
    done // <-- thats the callback method to let know when this task ends
  );
});

If the tasks need to be run in order the task name gets added as its own argument to runSequence if they don't conflict send them in as an array to have the tasks run at the same time and speed up your build process.

One thing to note about watch tasks! Typically watch tasks run indefinitely so trying to return the "infinite" stream from them may make gulp think that the task never ends. In that case I'll use the callback method to make gulp think the task is done even if it is still running, something like...

gulp.task( "watch-stuff", function( done ){
  gulp.watch( watchGlob )
    .on( "change", function( event ){ /* process file */ });

  done();
});

For more on watch tasks and how I do incremental builds check out an answer I wrote the other day, Incremental gulp less build

Community
  • 1
  • 1
ashwell
  • 224
  • 2
  • 13
  • Thanks for the lengthy reply. I have tried some of this before posting the question, but when i added the missing "return" to the streams, the stream broke. I have also tried run sequence, with no luck, possibly because I cant seem to get it to realise when a stream has ended. – James Steel Jan 28 '15 at 18:44
  • The only way I have got this to work is to pipe rsync onto the end of the sass magnification, and wrap it in gulp-if using a server: true variable so it only does the rsync if it knows its running on a VM. Not ideal. Maybe I will strip things back, rebuild carefully to see if i can figure out why the stream breaks with return added. – James Steel Jan 28 '15 at 18:51
  • It seems you are using rsync to sync to a local VM correct? Is there a reason Vagrant's synced_folder setup doesn't work for you? – ashwell Jan 28 '15 at 19:16
  • Yes - thats fine for me but may not be for others. This gulp setup is part of a framework i built. I want to allow the use of any local or remote development setup, not just vagrant. I'm the author of Midas http://midas.jamessteel.co.uk/ and this rsync feature is something i'm trying to roll in if i can get it to work, but i'm learning Gulp as I go. Midas is available on github, feel free to poke around if you have any ideas how to improve the gulp setup. :) I am using synced vagrant folder but want to keep the node_modules and everything out of it so i just copy CSS and JS over and Fonts. – James Steel Jan 28 '15 at 21:29
  • Well that's awesome! I will totally poke around when I find the time. – ashwell Jan 29 '15 at 01:51
0

Here you go, I believe it should work now. If not let me know, I might have made a typo. Your gist fixed

I think you are hitting (i don't have enough reputation points to post link, google issues #96) which is fixed in 4.x which isn't out yet :-). That said, check this hack out: My post about Gulp v3.x bug