Working with Gulp (2)

Jon Torrado
Sep 12, 2017 · 3 min read

After attending TheAntiEvent, I realized that the story I wrote some months ago about Gulp is quite different from the nowadays reality: https://medium.com/@jontorrado/working-with-gulp-step-by-step-e0d5fe2d2f23. I won’t write again about how to install Gulp, but I will update some of the tasks explained there and I will add some new.

SCSS to CSS transformation

Not a lot of changes here:

var gulp = require('gulp'),
autoprefixer = require('autoprefixer'),,
cssnano = require('cssnano'),
postcss = require('gulp-postcss'),
rename = require('gulp-rename'),

sass = require('gulp-sass'),
sasslint = require('gulp-sass-lint');
var paths = {
js: contexts.assets + '/js',
sass: 'app/Resources/assets/scss',
buildCss: 'web/css',
buildJs: 'web/js'
};
var watch = {
js: [
paths.js + '/**/*.js'
],
sass: [
paths.sass + '/**/*.scss'
]
};
gulp.task('sass', function () {
var plugins = [
autoprefixer({browsers: ['last 1 version']}),
cssnano()
];

return gulp.src(paths.sass + '/app.scss')
.pipe(sass())
.pipe(postcss(plugins))
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest(paths.buildCss));
});
gulp.task('sass-lint', function () {
return gulp.src(paths.sass + '/**/*.scss')
.pipe(sassLint())
.pipe(sassLint.format())
.pipe(sassLint.failOnError());
gulp.task('watch', function () {
gulp.watch(watch.sass, { interval: 500 }, ['sass']);
});

Before explaining what’s new here in comparison with the last story, be sure to add the needed dependencies (listed on the top part of the code above) in your file. In the previous code, you can read the following tasks:

  • sass: takes the main app.scss file, calls , then it minifies the result, adds a to the file name and moves it to the destination folder. The new elements: we are using postcss to add the vendor prefixes and to minify the resulting file. allows some configurations, such as .
  • sass-lint: if you are new to the lining world, WELCOME. With this task you will be able to detect SCSS errors (now with Node instead of Ruby). You must add your linting rules in an file. Check the example file here.
  • watch: this will automatically call the task whenever a file is modified. Just type to start watching. The interval parameter makes it lighter (good for SSD disks).

JavaScript bundling and minifying

Nothing changed here, almost.

There was an error in the previous story when using livereload. Gulp sent as many page reloads as the quantity of JavaScript files it processes. So, the question was, how to send just 1 page reload after finishing the whole JavaScript task? Here you have the solution:

var gulp = require('gulp'),
concat = require('gulp-concat'),
eslint = require('gulp-eslint'),
uglify = require('gulp-uglify');
// Paths in the code abovevar jsFiles = [
paths.js + '/**/*.js'
];
gulp.task('js', function () {
return gulp.src(jsFiles)
.pipe(concat('app.min.js'))
.pipe(uglify())
.pipe(gulp.dest(paths.buildJs));
});
gulp.task('eslint', function () {
return gulp.src(watch.js)
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
gulp.task('livereload-js', ['js'], function () {
livereload.reload();
});
gulp.task('watch', function () {
gulp.watch(watch.sass, { interval: 500 }, ['sass']);
gulp.watch(watch.js, { interval: 500 }, ['js', 'livereload-js']);
});

As you see, the new task depends on , so before launching it, it will wait for the task to finish. Awesome!

Launching binary files

Maybe you want to use Gulp for every single task, even the binary files (or execute files too!). You can accomplish that goal with the following code:

var cp = require('child_process');gulp.task('binary', function () {
return cp.execFile('bin/binary', ['--option=value'], function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
});
});

Plumber

Plumber will replace your method and catch the launched that breaks the execution (for example, when you do something wrong and the method stops). Is just this simple:

// ... plumber = require('gulp-plumber')gulp.task('sass', function () {
var plugins = [
autoprefixer({browsers: ['last 1 version']}),
cssnano()
];
return gulp.src(paths.sass + '/app.scss')
.pipe(plumber())
.pipe(sass())
.pipe(postcss(plugins))
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest(paths.buildCss));
});

Including other Gulpfile.js

If you are working in a big project with some separated submodules (for example, website and admin), you may want to have one that includes the others. Here is how you can do that:

var gulp = require('gulp');
var chug = require('gulp-chug');
var argv = require('yargs').argv;
config = [
'— rootPath',
argv.rootPath || '../../../../web/assets/',
'— nodeModulesPath',
argv.nodeModulesPath || '../../../../node_modules/'
];
gulp.task('admin', function() {
gulp.src('submodule/path/to/Admin/Gulpfile.js', { read: false })
.pipe(chug({ args: config }))
;
});

Convert images to WebP

You should be using images with the tag to allow Chrome users navigate much faster (and consume less bandwith!). You can automate the process of transforming images to webp.

var gulp = require('gulp'),
webp = require('gulp-webp');

gulp.task('default', function() {
gulp.src('path/to/images/**.jpg')
.pipe(webp())
.pipe(gulp.dest('dist'))
});

Other useful plugins

Here you have a curated list of useful gulp plugins you should read about carefully: https://gist.github.com/renarsvilnis/ab8581049a3efe4d03d8.

Jon Torrado

Written by

CTO and co-owner at GamersWalk — IT lover