As mentioned in my earlier post Gulp js interview questions, Gulp tasks are asynchronous. Which means that we are not sure about sequence of gulp tasks execution while chaining multiple tasks. And if you have used Grunt then it’s a tricky situation to handle for you as Grunt tasks are synchronous by design. So in this post, find how to run gulp tasks synchronously.
How to run gulp tasks synchronously
It is a common practice to define a default task in gulp to perform the set of tasks together. And it’s quite possible that some tasks are independent and some task depends on other task. Consider following gulp file,
var gulp = require('gulp'); var sass = require('gulp-sass'); var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); var rename = require('gulp-rename'); var rimraf = require('gulp-rimraf'); //Clear folder. gulp.task(‘clean’, function (cb) { rimraf('dest\*', cb); }); // Compile Sass gulp.task('build-css', function() { return gulp.src('scss/*.scss') .pipe(sass()) .pipe(gulp.dest('dest')); }); // Concatenate & Minify JS gulp.task('build-scripts', function() { return gulp.src('js/*.js') .pipe(concat('all.js')) .pipe(gulp.dest('dist')) .pipe(rename('all.min.js')) .pipe(uglify()) .pipe(gulp.dest('dest')); });
Below is the syntax to create a default task.
gulp.task('default', ['clean', 'build-css', 'build-scripts']);
There are 3 tasks but here we are not sure about their order execution as gulp tasks run in parallel (all at once), so don’t assume that the tasks will start/finish in order. Ideally we would expect them to run in following order clean -> build-css -> build-scripts.
Imagine what would happen if the order becomes “build-css -> clean -> build-scripts” or “build-scripts -> build-css -> clean”? We will end having an empty folder for your js and css resources. And that’s what we don’t want. So how do we fix this? There are 2 ways to solve this issue.
Creating dependency
As explained in Q.15 of Gulp js interview questions, gulp.task
has 3 forms. And one of them is,
gulp.task('mytask', ['array', 'of', 'task', 'names'], function() { //do stuff . });
2nd argument in gulp.task
is an array to define task dependencies. We can inform gulp that this task is dependent on one or more tasks so wait for them to finish first, before you start this task. So, if we modify our existing “build-css” and “build-scripts” task,
gulp.task('build-css','[clean]', function() { //do stuff}); gulp.task('build-scripts','[clean]', function() { //do stuff });
So now build-css
task will get executed only when clean is finished and same is true for build-scripts
task. Much better now. But there is a problem with this Fix , which you will see in next solution.
Using run-sequence plugin
Let’s say, you have also defined a watch task.”Watch task is responsible for watching the files/folder changes and then automatically run our tasks.” Watch task is watching the changes for js folder (where JavaScript files are present) and Sass folder.
// Watch Files For Changes gulp.task('watch', function() { gulp.watch('js/*.js', ['build-scripts']); gulp.watch('scss/*.scss', ['build-css']); });
Whenever any js file changes, watch task will run build-script
task. As build-script task has dependency on clean
task, so it will wait for clean
to finish. But the problem is, clean
task will delete all the files the “dest” directory including our css file. So to fix this, we have to again remove the task dependency. And if we do that then we are back to same problem.
The fix is to use run-sequence. This allows you to runs a sequence of gulp tasks in the specified order.
var runSeq = require('run-sequence'); gulp.task('copy-and-concat', function(){ return runSeq(clean', ['build-css', ' build-scripts']); });
Now, clean
task will always executed first and build-css
and build-script
task can run in parallel. And remember we also need to remove task dependency as well.