Task Order
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Look at the default task. The array defines task dependencies: Gulp runs
each of these first, waits for them to finish, and then executes the callback
for the task, if there is one. And based on the output, it looks like it
runs them in order: clean, then styles, then scripts.
Is that true?
There is no Order to Dependent Tasks
Log a message once fonts is done:
| // ... lines 1 - 112 | |
| gulp.task('fonts', function() { | |
| app.copy( | |
| config.bowerDir+'/font-awesome/fonts/*', | |
| 'web/fonts' | |
| ).on('end', function() {console.log('finished fonts!')}); | |
| }); | |
| // ... lines 119 - 134 | 
And also add a message right when the watch task starts:
| // ... lines 1 - 126 | |
| gulp.task('watch', function() { | |
| console.log('starting watch!'); | |
| gulp.watch(config.assetsDir+'/'+config.sassPattern, ['styles']); | |
| gulp.watch(config.assetsDir+'/js/**/*.js', ['scripts']); | |
| }); | |
| // ... lines 132 - 134 | 
The default task defines fonts then watch, and I want to see if that
order matters.
Ok, try it!
gulp
It exploded! It say we're calling on on something undefined. This happens
with our code because up in app.copy, we're not returning the stream. So
yea, that would be undefined:
| // ... lines 1 - 48 | |
| app.copy = function(srcFiles, outputDir) { | |
| return gulp.src(srcFiles) | |
| .pipe(gulp.dest(outputDir)); | |
| }; | |
| // ... lines 53 - 134 | 
Ok, now try it. It's all out of order! Even though fonts is listed
before watch in the dependency list, watch starts way before fonts
finishes. In reality, Gulp reads the dependent tasks for default, then
starts them all at once. Once they all finish, default runs.
But what if we needed fonts to finish before watch started? Well, it's
the same trick: add fonts as a dependency to watch:
| // ... lines 1 - 126 | |
| gulp.task('watch', ['fonts'], function() { | |
| // ... lines 128 - 130 | |
| }); | |
| // ... lines 132 - 134 | 
Try it out:
gulp
But surprise! It's still running out of order. Here's the reason: if you're
dependent on a task like fonts, that task must return a Promise or a
Gulp stream. If it doesn't, Gulp actually has no idea when fonts finishes
- so it just runs watchright away. So,return app.copyfrom thefontstask, sinceapp.copyreturns a Gulp stream.
| // ... lines 1 - 112 | |
| gulp.task('fonts', function() { | |
| return app.copy( | |
| // ... lines 115 - 116 | |
| ).on('end', function() {console.log('finished fonts!')}); | |
| }); | |
| // ... lines 119 - 134 | 
Now, Gulp can know when fonts truly finishes its work.
Ok, try it once more:
gulp
There it is! fonts finishes, and then watch starts. And there's one
more thing: Gulp finally prints "Finished 'fonts'" in the right place, after
fonts does its work.
Why? It's not that Gulp was lying before about when things finished. It's that Gulp can't report when a task finishes unless that task returns a Promise or a Gulp stream. This means we should return one of these from every task.
We don't need the fonts dependency, so take it off. And remove the logging:
| // ... lines 1 - 112 | |
| gulp.task('fonts', function() { | |
| return app.copy( | |
| config.bowerDir+'/font-awesome/fonts/*', | |
| 'web/fonts' | |
| ); | |
| }); | |
| // ... lines 119 - 126 | |
| gulp.task('watch', function() { | |
| // ... lines 128 - 129 | |
| }); | |
| // ... lines 131 - 133 | 
So if we should always return a stream or promise, how can we do that for
styles? It doesn't have a single stream - it has two that are combined
into the pipeline. We need to wait until both of them are finished.
Oh, the answer is so nice: just return pipeline.run():
| // ... lines 1 - 84 | |
| gulp.task('styles', function() { | |
| var pipeline = new Pipeline(); | |
| // ... lines 87 - 98 | |
| return pipeline.run(app.addStyle); | |
| }); | |
| gulp.task('scripts', function() { | |
| var pipeline = new Pipeline(); | |
| // ... lines 104 - 109 | |
| return pipeline.run(app.addScript); | |
| }); | |
| // ... lines 112 - 133 | 
This isn't magic. I wrote the Pipeline code, and I made run() return a
Promise that resolves once everything is done. And if you know anything
about promises, the guts should make sense to you. But if you have questions,
just ask in the comments.
Make sure we didn't break anything.
gulp
Yep, it all still looks great. So if you eventually need to create a task
that's dependent on styles or scripts finishing first, it'll work.
 
    
         
            
Hey Ryan. Very detailed tutorial, thanks. Switched from Assetic to Gulp.
I have experienced small problem with browserSync and cache busting - browserSync forces full page reload with versioning in dev environment. (Instead of Css injection) So, I have modified config: (All files are commented)
https://github.com/nix23/gu...
Shortly, I have added/modified following:
1) Added ability to execute console commands in order with Pipeline class; (If some command fails, command execution stops)
2) Added browserSync Gulp integration with Css injection support;
3) Modified AssetExtension class - now css/js assets are versioned only in prod environment, because dynamic name change will force browserSync to perform full page reload instead of Css injection on sass/css file changes;
4) Extended FosJsRoutingBundle to override initialize method in dump command and inject target arg to InputInterface object. (We want apply versioning to 'fos_js_routes.js' file as well on production environment);
Hope, this helps someone. ;)
Cheers!