Can I use Gulp 4 to run tasks in a serial fashion? - gulp

My code currently uses run-sequence to run a series of tasks. From what I was told I can now do this using native Gulp 4. Can someone confirm if this is possible and if so advise how I could do this.
var runSequence = require('run-sequence');
gulp.task('make-prod-ex1', function () {
makeAppHtml('app/**/*ex1', function () {
runSequence(
'makeTemplate',
'clean-css',
'make-css-files',
'make-css-bundle',
'rename-css-bundle',
'clean-js',
'make-js-bundle',
'rename-js-bundle',
'rename-index',
function () {
console.log("Completed");
});
});
});

In Gulp 4.0 gulp.series() and gulp.parallel() completely replace the task dependency mechanism that was used in Gulp 3.x. That means you can't write things like gulp.task('task1', ['task2']) anymore.
Instead of telling Gulp which tasks depend on each other and letting Gulp decide the execution order based on the dependency graph, you now have to explicitly define the execution order by composing gulp.series() and gulp.parallel() calls. Both can accept task names as well as functions and return functions themselves:
gulp.task('make-prod-ex1', gulp.series(
function(done) {
makeAppHtml('app/**/*ex1', done);
},
'makeTemplate',
'clean-css',
'make-css-files',
'make-css-bundle',
'rename-css-bundle',
'clean-js',
'make-js-bundle',
'rename-js-bundle',
'rename-index',
function (done) {
console.log("Completed");
done();
}));
As usual you have to make sure to signal async termination by either calling a done callback or returning streams in your tasks/functions. From personal experience it seems that Gulp 4.0 is a lot more quick to complain about this than Gulp 3.x was.

Related

Are tasks in gulp run in sequences?

Basic question but i just cannot find answer yet.
var gulp = require('gulp');
gulp.task('one', function(cb) {
// do stuff -- async or otherwise
cb(err);
});
gulp.task('two', function(cb) {
// do something
cb(err)
});
gulp.task('three', function(cb) {
// do something
cb(err)
});
The Q is: does task 2 only runs when task 1 finishes, task 3 only runs when task 2 finishes ?
With just this setup, only one task will be executed at all, e.g. task two if you invoke gulp two.
You can create composite tasks with the help of the functions series(...) and parallel(...) provided by Gulp. The new task will run the tasks passed to the function either in sequence or in parallel. Calls to the functions can be nested to create more complex scenarios.

Gulp - conditional task inside task

I'd like to set up my default task to run with watch task if environment is set production. I can't find solution to make my gulp-if conditional work in a tasks stack. Here's my code:
gulp.task('default', ['styles', 'scripts', 'video' ], function() {
gulpif(isProduction, gulp.task('watch'));
});
Instead of gulp.task('watch') use gulp.start('watch') although you usually don't want to call a task from another task. A better way would be for you to create a function and call the function instead.
Also note: the gulp.start() method will no longer work with gulp4
Update:
Here is an example of how to use functions within gulp:
var someFile = require('./someFile.js');
gulp.task('my-custom-task', function () {
someFile.doSomething('foo', 'bar');
});
If your function does something asynchronously, it should call a callback at the end, so gulp is able to know when it’s done:
var someFile = require('./someFile.js');
gulp.task('my-custom-task', function (callback) {
someFile.doSomething('foo', 'bar', callback);
});

gulp.watch - To return or not return

The official documentation for gulpjs/gulp has a sample gulpfile.js which provides a watch task that has no return statement:
gulp.task('watch', function() {
gulp.watch(paths.scripts, ['scripts']);
gulp.watch(paths.images, ['images']);
});
That approach fits my needs, because I want to watch over multiple sets of files with different tasks associated to each of them.
But I've found in the community a few bold statements saying that gulp.watch should be returned, such as this one, that proposes the following code:
gulp.task('watch', function() {
return gulp.watch('./public/resources/jsx/project/*.js',['application'])
});
I understand that tasks should return, so that other tasks using them as part of their workflow are able to act accordingly to their async nature, but for the special case of a watch task, which is always the last in a list of tasks, there might make sense not to return it, making it possible to have multiple watches.
Does that make sense? Can I safely omit the return from my watch task in order to be able to have multiple instances of gulp.watch in it?
I prefer all task have return statement. Otherwise you can read a false "Finished watch".
When task are complex, it is not possible create a single watch for a several pattern of files. In this cases, my solution is based on to create a supergroup task called "watch" that depends on single watches with its return statements.
gulp.task("watch", [
"watch-css",
"watch-js",
"watch-inject-html"
]);
gulp.task("watch-css", function() {
return gulp.watch(sources.css, ["css"]);
});
gulp.task("watch-js", function() {
return gulp.watch(sources.js, ["js"]);
});
gulp.task("watch-inject-html", function() {
return gulp.watch(sources.inject, ["inject-html"]);
});
For gulp4 you can do this:
gulp.task('watch:images', gulp.parallel(
function () { return gulp.watch(SRC_DIR+'/*', gulp.task('images:copy')); },
function () { return gulp.watch(SRC_DIR+'/svg/**/*', gulp.task('images:svg')); },
function () { return gulp.watch(SRC_DIR+'/backgrounds/**/*', gulp.task('images:backgrounds')); },
function () { return gulp.watch(SRC_DIR+'/heads/**/*', gulp.task('images:heads')); }
));
However the anonymous functions inside gulp.parallel will report as <anonymous> in gulp output.
You can give the functions names and they will show up in gulp output instead of anonymous.
gulp.task('watch:images', gulp.parallel(
function foobar1 () { return gulp.watch(SRC_DIR+'/*', gulp.task('images:copy')); },
function foobar2 () { return gulp.watch(SRC_DIR+'/svg/**/*', gulp.task('images:svg')); },
function foobar3 () { return gulp.watch(SRC_DIR+'/backgrounds/**/*', gulp.task('images:backgrounds')); },
function foobar4 () { return gulp.watch(SRC_DIR+'/heads/**/*', gulp.task('images:heads')); }
));
However it seems that return gulp.watch(/* ... */) is not ideal. When watching if you hit CTRL-C you get a nice big error about those watch tasks not completing.
It seems like if you have a stream you are supposed to return the stream.
e.g. return gulp.src(...).pipe()
...but if you are doing something async or don't have a stream you should be calling the callback instead of returning something.
Would be happy to be pointed to the relevant docs for this (return vs callback) as I didn't see a clear explanation in the gulp docs I read. I tried going all callback (no returning streams) and ran into other issues...but possibly they were caused by something else.
Dealing with multiple watches in a single task the following way doesn't report <anonymous> and also doesn't complain when you CTRL-C while watching. My understanding is that since the watch tasks are open-ended we just inform gulp that as far as gulp cares when it comes to making sure stuff runs in a specific order, these are started and gulp can move on.
gulp.task('watch:images', function (done) {
gulp.watch(SRC_DIR+'/*', gulp.task('images:copy'));
gulp.watch(SRC_DIR+'/svg/**/*', gulp.task('images:svg'));
gulp.watch(SRC_DIR+'/backgrounds/**/*', gulp.task('images:backgrounds'));
gulp.watch(SRC_DIR+'/heads/**/*', gulp.task('images:heads'));
return done();
});
I think you can omit return for watch task. I also don't support structures that has multiple watches. More over you are only going to use watch task on development environment, so go ahead and ignore return for watch task.

How to run gup task in series

I am new to gulp.
I have written two task that need to be performed. When I run them separately, they work fine. But when I combine them, the "replace" does not work.
gulp.task('bundle-source', function () {
return bundler.bundle(config);
});
gulp.task('bundle-config', function(){
return gulp.src(['config.js'])
.pipe(replace('src/*', 'dist/*'))
.pipe(gulp.dest(''));
});
gulp.task('bundle', ['bundle-config', 'bundle-source']);
I think the issue is that they both manipulate config.js. I think the second task when it saves to disk overwrites the change the first one made. The second task is about 30 seconds.
Gulp tasks are run in parallel by default. So if your tasks are working on the same files, they might step on each others' toes indeed.
You can use gulp's tasks dependencies to have them run one after the other. So if bundle-config should be run before bundle-source :
gulp.task('bundle-source', ['bundle-config'], function () {
return bundler.bundle(config);
});
You can also use a package like run-sequence if you need them to run one after the other :
var seq = require('run-sequence');
gulp.task('bundle', function(cb) {
return seq('bundle-config', 'bundle-source', cb);
});
Finally, You could use gulp 4, which has a built-in mechanism to run tasks in series.

Gulp consecutive tasks as stream

Basically, I have tasks split in two. The first is for development. There’s no magic, just basic stuff to make it work. It’s fast and great. The latter is for production. It’s slow, and I only want to run it periodically for testing, debugging, optimisation and production. Hence they are two separate tasks.
The latter, the task for production, does rely on the former task, however, I’d like to continue the stream, as if the latter task is an addition to the former.
gulp.task('styles', function() {
return gulp.src('src/sass/**/*.scss')
.pipe(sass())
.pipe(autoprefixer())
.pipe(gulp.dest('dist/css'));
});
gulp.task('styles-production', function() {
return runTaskAndUseStream('styles')
// Continue where the styles task ended
.pipe(uncss({
...
}))
.pipe(gulp.dest('dist/css'));
});
I was hoping the undocumented gulp.start('task') method would return a stream, but unfortunately it doesn’t. Many modules does allow you to fiddle with streams, but none of them returns a gulp task as a stream.
What do?
One thing that is (most likely) considered best practice would be incorporating the uncss task into your styles task, but running it only when certain flags are set:
var gutil = require('gulp-util');
function production(task) {
return (gutil.env.production ? task : gutil.noop());
}
gulp.task('styles', function() {
return gulp.src('src/sass/**/*.scss')
.pipe(sass())
.pipe(autoprefixer())
.pipe(production(uncss({
})))
.pipe(gulp.dest('dist/css'));
});
Packages you need: gulp-util for the noop task, and argument parsing
run it with gulp styles --production
(untested, but you get the concept)