loading...
Cover image for Make your builds quicker with Gulp 4

Make your builds quicker with Gulp 4

khalyomede profile image Khalyomede ・4 min read

Gulp version 4 is out! The migration is pretty straight forward and involves minimum breaking changes while bringing one very useful feature: to be able to parallelize tasks.

Upgrading from 3 to 4

You can follow one of the most popular Medium post on making the transition successfuly.

Sam also wrote on his recipe on how to make the transition a breeze.

Compressing images with Gulp 3

Before Gulp 4, this is what you might have done to compress images.

const gulp = require("gulp");
const imagemin = require("gulp-imagemin");
const webp = require("gulp-webp");

gulp.task("pictures", function() {
  return gulp.src("src/img/**/*.{jpg,jpeg,png,svg}")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("webp", function() {
  return gulp.src("src/img/**/*.{jpg,jpeg,png}")
    .pipe(webp())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("img", ["pictures", "webp"]);

Which means

Compress my jpeg, png and svg files one by one, and wait before they are all compressed before converting them into webp.

Which is fine, but the main caveat is that your picture tasks will have to process all your images one by one.

If we think about it, we could split our process by file types: png, jpeg, svg. This is possible because gulp-imagemin uses different libraries to compress images (SVGO, PNGQuant, JPEGTran).

Compressing images with Gulp 4

First let us keep the same algorithm, and use the new gulp.series() method.

const gulp = require("gulp");
const imagemin = require("gulp-imagemin");
const webp = require("gulp-webp");

gulp.task("picture", function() {
  return gulp.src("src/img/**/*.{png,jpg,jpeg,svg}")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("webp", function() {
  return gulp.src("src/img/**/*.{png,jpg,jpeg}")
    .pipe(webp())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("img", gulp.series("picture", "webp"));

Doing the same, but with modern methods

If you run gulp img on your console, you will have the same output. Now we use the latest Gulp 4 features, pretty straight forward migration!

Let us split up our picture task.

const gulp = require("gulp");
const imagemin = require("gulp-imagemin");
const webp = require("gulp-webp");

gulp.task("png", function() {
  return gulp.src("src/img/**/*.png")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("jpg", function() {
  return gulp.src("src/img/**/*.{jpg,jpeg}")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("svg", function() {
  return gulp.src("src/img/**/*.svg")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("webp", function() {
  return gulp.src("src/img/**/*.{png,jpg,jpeg}")
    .pipe(webp())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("img", gulp.series("png", "jpg", "svg", "webp"));

Again, nothing changed, only making it more easier for what comes next.

Now the fun part: let us make the 3 first tasks run in parallel.

const gulp = require("gulp");
const imagemin = require("gulp-imagemin");
const webp = require("gulp-webp");

gulp.task("png", function() {
  return gulp.src("src/img/**/*.png")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("jpg", function() {
  return gulp.src("src/img/**/*.{jpg,jpeg}")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("svg", function() {
  return gulp.src("src/img/**/*.svg")
    .pipe(imagemin())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("webp", function() {
  return gulp.src("src/img/**/*.{png,jpg,jpeg}")
    .pipe(webp())
    .pipe(gulp.dest("dist/img"));
});

gulp.task("img", gulp.series(gulp.parallel("png", "jpg", "svg"), "webp"));

Which means:

Compress all the png, jpg and svg files in whatever order you want, but wait for all before starting converting them into webp.

Using the new gulp.parallel(), this is a piece of cake to perform parallelized tasks!

Going further

Now this is better, but there is still one little thing that bugs me. If you noticed, this is the blob used for our pictures:

".{png,jpg,jpeg,svg}"

But the webp blob is missing the svg:

".{png,jpg,jpeg}"

I did this on purpose because I do not want to convert my SVG files into WebP: they are perfect to respond to responsiveness while keeping a high quality so I do not want to loose this feature.

This also means our that webp task does not have to wait before svg to finish to be compressed. So we could add another optimization layer like following.

gulp.task('picture', gulp.parallel('png', 'jpg'));

gulp.task('img', gulp.parallel(gulp.series('picture', 'webp'), 'svg');

Which means:

Compress SVG files in the same time as compressing jpg and png files with webp waiting for jpg and png files before converting them into webp.

Conclusion

I love Gulp for its great user experience. Building complex bundling logic is just so neat and clear.

Check out the documentation if you want to know more about gulp and all its features, including watching file changes and perform tasks as you update a file, and plenty more.

Gulp also supports modern Javascript notation, so you might want to write your fancy tasks like:

const { src, dest, series, parallel } = require("gulp");
const imagemin = require("gulp-imagemin");
const webp = require("gulp-webp");

const png = () => src("src/img/**/*.png")
  .pipe(imagemin())
  .pipe(dest("dist/img"));

const jpg = () => src("src/img/**/*.{jpg,jpeg}")
  .pipe(imagemin())
  .pipe(dest("dist/img"));

const webp = () => src("src/img/**/*.{png,jpg,jpeg}")
  .pipe(webp())
  .pipe(dest("dist/img"));

const img = series(parallel(png, jpg), webp);

module.exports = { img };

I hope you are as amazed as I am about those new features! Happy bundling!

Posted on Mar 2 '19 by:

khalyomede profile

Khalyomede

@khalyomede

Fullstack developer @ Carlili

Discussion

markdown guide