UI/UX Design

How to configure a Gulpfile.js – [ Basic tutorial for beginners ]

 

Few days ago I tried Gulp for the first time and I spent few hours playing with it. I used Grunt before and I liked it so I was a bit sceptical about Gulp and its benefits.

In this post I want to show you some things I learnt about Gulp and how to configure your gulpfile.js file.

 

Why should you choose Gulp over Grunt?

There are 2 reasons for this:

  • After reading about Gulp and playing with it, I can confirm that it is faster than Grunt. One of my task ran in 2 seconds with Grunt and it only took 250ms with Gulp.
  • Gulp doesn’t have to be installed globally and can be installed as a Node module only. As far as I understood, Grunt 1.0 finally also gives this option but is probably a bit too late now,

 

How to start?

The firs step is to generate a package.json file which will take care of your dependencies.

The minimum code you need for that is just this:

  
  
{
  "version": "1.0",
  "scripts": {
    "gulp": "gulp"
  }
}
  

This will allow you to run Gulp without installing it globally using the npm run gulp command.

In the same folder where package.json is, open a Terminal/Console window and install Gulp using the command: npm i -D gulp. You can also install Gulp globally using the npm i -g gulp command.

Create a new file called gulpfile.js and add the minimum required code which is:

  
  
var gulp = require('gulp');

gulp.task('default', function() {

});
  

Now that you have the minimum required configuration you can use the command npm run gulp or just gulp if you installed it globally. Nothing will happen because there are no tasks added yet.

 

What should Gulp do?

Javascript
– Run JSHint to help detect errors and potential problems in code.
– Concatenate the javascript files to reduce application loading time.
– Minify the javascript files to reduce the file size and load faster.
– Generate a sourcemap to map the positions (line and column) and names in transformed sources back to the original files.

CSS
– Compile Sass into CSS
– Run the Autoprefixer to prefix the CSS for specific browsers
– Generate a sourcemap to map the positions (line and column) and names in transformed back to the original file.

Others
– Cleaning (removing the compiled documents);
– Watch ( with livereload ) – This is a file watcher that uses super-fast chokidar and emits vinyl objects.
– Copy different files (e.g. images or fonts);
– The JS and CSS will be generated in a normal format and also a minified version.

 

How to start

For this example we want to have a project structure that looks like this:

  
  
- gulpfile.js
- package.json
- src
    \---assets
        +---img
        +---fonts
        +---js
        |   \---vendor
        |   \---main
        +---css
            \---style
            \---responsive
  

 

First let’s install the plugins that are common in most tasks by running this command in your Terminal:
npm i -D gulp-util gulp-sourcemaps gulp-clone gulp-plumber merge-stream gulp-rename path fs

After the installation is finished, update gulpfile.js to require the plugins:

  
  
var gulp = require('gulp');
var livereload  = require('gulp-livereload');
var plumber = require('gulp-plumber');
var rename = require('gulp-rename');
var gutil = require('gulp-util');
var clone = require('gulp-clone');
var merge = require('merge-stream');
var sourcemaps = require('gulp-sourcemaps');
var path = require('path');
var fs = require('fs');
  

In the same file we’ll add the following function which will help with displaying the errors without stopping the tasks:

  
  
function err(error) {
  var displayError = gutil.colors.red(error.message);
  gutil.log(displayError);
  gutil.beep();
  this.emit('end');
}
  

To keep the file as clean as possible we will define all files and folders in a multidimensional array:

  
  
var srcFiles = {
  scripts : {
    defaultDest: 'dist/assets/js',
    main : {
      files: ['src/assets/js/main/**/*.js'],
      dest: 'dist/assets/js2',
      skipLint: false
    },
    utils: [],
    admin : [],
    vendor : []
  },

  stylesheets: {
    defaultDest: 'dist/assets/css',
    screen : {
      files: ['src/assets/css/style/global.scss'],
      watch: ['src/assets/css/style/**/*.scss'],
      dest: 'dist/assets/css2'
    },
    grid : [
      'src/assets/css/responsive/grid.scss'
    ]
  },

  assets: {
    images : ['src/assets/img/**/*'],
    fonts : ['src/assets/fonts/**/*'],
  }
};
  

For both javascript and css we can specify the destination for compiled files. Javascript has another option which can be enabled if needs to be linted. For CSS there is a watch which will monitor all the files in the folder.

 

Install the css plugins

To install the css plugins run the following command in Terminal:
npm i -D gulp-sass autoprefixer gulp-postcss gulp-cssmin

After that, in gulpfile.js require the new plugins:

  
  
var cssmin = require('gulp-cssmin');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer');
var sass = require('gulp-sass');
  

The next step is to compile the sass into css and use the plumber and clone plugins to save 2 versions of css files, one minified and another one which is not minified.

To do that we will write a function that contains 2 tasks:
– First task will compile the sass into css, generate the sourcemap and save the files
– Second task will minify the files, rename the files, generate the sourcemaps and save the files

  
  
function sassTask(name) {
  var dest = srcFiles.stylesheets[name].dest || srcFiles.stylesheets.defaultDest;
  var source = gulp.src(srcFiles.stylesheets[name].files)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(sass({ outputStyle: 'expanded' })).on('error', err)
    .pipe(postcss([
      autoprefixer({browsers: ['last 2 versions']}),
    ]));

  var pipe1 = source.pipe(clone())
    .pipe(sourcemaps.write('.', { sourceRoot: null }))
    .pipe(gulp.dest(dest));

  var pipe2 = source.pipe(clone())
    .pipe(cssmin())
    .pipe(rename({suffix: '.min'}))
    .pipe(sourcemaps.write('.', { sourceRoot: null }))
    .pipe(gulp.dest(dest));

  return merge(pipe1, pipe2).pipe(livereload());
}
  

Now we can register new tasks just by using something like:

  
  
gulp.task('sass:style', function () {
  return sassTask('style');
});

gulp.task('sass:responsive', function () {
  return sassTask('responsive');
});
  

We can also group all the CSS tasks into a single task like:

  
  
gulp.task('sass', ['sass:style', 'sass:responsive']);
  

Because this could become a little messy when the project grows, let’s create a function which will group the tasks:

  
  
function groupTasks(taskName) {
  return Object.keys(gulp.tasks).filter(function(task){
    return task.indexOf(taskName) != -1;
  });
}
  

Now we can simply group the tasks by using the function like this:

  
  
gulp.task('sass', groupTasks('sass:'));
  

 

Install the javascript plugins

For javascript we will use the same strategy which we used for css. We create a function and reuse it when needed.

First install the plugins by running the following command in Terminal:
npm i -D jshint gulp-jshint gulp-concat gulp-uglify jshint-stylish

and require them in gulpfile.js

  
  
var cssmin = require('gulp-cssmin');
var concat = require('gulp-concat');
var stylish = require('jshint-stylish');
var uglify = require('gulp-uglify');
var jshint = require('gulp-jshint');
  

Now we create a function which will contain 2 tasks. First task will concatenate the files and the second task will uglify them. Optionally you can skip linting for example for files which are not yours.

  
  
function scriptTask(name) {
  var dest = srcFiles.scripts[name].dest || srcFiles.scripts.defaultDest;
  var filesSource = gulp.src(srcFiles.scripts[name].files);

  if (!srcFiles.scripts[name].skipLint) {
    filesSource = filesSource.pipe(jshint()).pipe(jshint.reporter('jshint-stylish'));
  }

  filesSource = filesSource.pipe(sourcemaps.init())
    .pipe(concat(name + '.js'));

  var pipeClone = filesSource.pipe(clone())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(dest));

  var pipeUglify = filesSource.pipe(clone())
    .pipe(rename({
      basename: name,
      suffix: '.min'
    }))
    .pipe(uglify()).on('error', err)
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(dest));

  return merge(pipeClone, pipeUglify).pipe(livereload());
}
  

add and group the tasks similar to css

  
  
gulp.task('scripts:main', function() {
  return scriptTask('main');
});

gulp.task('scripts:vendor', function() {
  return scriptTask('vendor');
});

gulp.task('scripts', groupTasks('scripts:'));
  

 

Other things you can do

Cleaning
There are many times when you will need to clean all the compiled files from the dist folder. For that you can install the rimraf plugin by running the command:

npm i -D gulp-rimtaf

in gulpfile.js require the plugin:

  
  
var fs = require('fs');
var rm = require('gulp-rimraf');
  

then create a new task which can be run to remove the files

  
  
gulp.task('clean', function() {
  return gulp.src(['dist']).pipe(rm());
});
  

Now create a new task called build which will first clean the folder and then run the other tasks to generate new files.

  
  
gulp.task('build', ['clean'], function(){
  gulp.start(['scripts', 'sass']);
});
  

modify the default task aswell to run the build task first

  
  
gulp.task('default', ['build'], function() {
  // ...
});
  

Why do you need all these tasks?
Because we want to run gulp once (build) and also in real time when a file is modified (watch).

Add comment