Using Gulp to Make Frontend Tolerable

Automate tasks for production deployment such as compiling your CSS and JS

Alright fine, so maybe the whole obligatory-gulp-tutorial-on-some-coding-blog thing has become a bit cliché at this point. Hate all you want, but I 'll take all the traffic from keywords I can get at this point. Keywords such as Gulp, or ExpressJS, or  NodeJS, or React Vue frontend ubuntu installation API social cloud data entrepreneur community. Hopefully this serves as a good reference regardless, like when we copy/paste our gulpfiles from project to project and forget what they actually do.

Quick 101

NodeJS developers use Gulp to automate necessary processes before moving their frontend code to production. This includes minifying files to make them run faster, and to also make them unreadable to people who would otherwise make fun of your mediocre Javascript which you were forced to crank out on a short timeline.

General Workflow

Let's say you're running a basic Express app. As opposed to developing and storing files in a directory such as /public, Gulp enables us to develop in one directory, and compile to another. That means we can keep our horrible uncompressed and uncompiled  source in a folder such as /src, and output them to a directory such as /dist, which would be our public-facing output. An Express file structure utilizing this would look something like this:

  |- src/
      |- js/ 
      |- scss/
  |- dist/
      |- js/ 
      |- css/
      |- img/
      |- fonts/
  |- views
      |- index.hbs
  |- routes
      |- index.js
  |- gulpfile.js
  |- node_modules/
  |- package.json
  |- app.js

Installation

First install the gulp CLI:

npm install --global gulp-cli

Next, enter your project folder and install gulp while saving it as  a project dependency.

npm install --save gulp

How it Works

Without any plugins, Gulp doesn't do anything on its own. Gulp is essentially a process wrapper which executes the tasks you so desire; this entails a bit of setup, but it also makes Gulp highly customizable to your needs.

The Gulpfile

Gulp works by invoking a file called gulpfile.js in your main directory, which you'll need to create and set up yourself (sorry). The file is divided into two main parts: requiring (importing) plugins, and defining which tasks to run when gulp is invoked. A basic worthless gulpfile might look something like:

var gulp = require('gulp');

gulp.task('default', function () {
  console.log('Sup World!');
});

To make this file useful, we'll need to install more plugins and set up tasks for them.

Essential Plugins

Let's look at what each one does. Keep in mind there are thousands of Gulp plugins, so let's just touch on the big hitters here.

Keep in mind to install any of these plugins, you'll simply need to run the npm installation in your project directory:

npm install --save [plugin name]

gulp-uglify

Minifies Javascript or CSS files, and outputs the result into the directory of your choice. This plugin can be reused across filetypes, as we'll demonstrate in a moment.

gulp-concat

Combines minified files into a single file. This is essential for browser performance as it reduces the number of http requests being made every time your page loads.

gulp-rename

Renames files (such as those produced by gulp-concat).

gulp-sass / gulp-less

Compiles your Sass or Less files into CSS and outputs to the directory of your choice.

gulp-minify-css

Minifies CSS, as you might imagine. This can chained to gulp-sass or gulp-less to minify the CSS files those tasks produce.

gulp-autoprefixer

Thank god for this. Autoprefixer finds CSS styles and adds the browser-specific equivalents to your CSS, so you don't need to write the same style 10 times for every horrible browser in existence. This means you can write styles such as:

background: linear-gradient(to bottom, white, black);

And have them output as:

background: -webkit-gradient(linear, left top, left bottom, from(white), to(black));
background: -webkit-linear-gradient(top, white, black);
background: -o-linear-gradient(top, white, black);
background: linear-gradient(to bottom, white, black);

gulp-watch

Allows Gulp to listen for changes being made to source files, so that it may fire an event upon file change, such as:

gulp-livereload

Compiles the changes made in directories being watched via gulp-watch automatically while you work.

Next Level Pro Shit

While these plugins aren't 'essential', they are really cool and helpful.

gulp-sourcemaps

An obnoxious side effect of minifying and concating your files is when it comes time to debug errors on the frontend. Errors occurring at "line 235" are pretty useless considering your error codes are referring to the compiled files, without granting a hint as to where the problematic code may have come from in the first place. gulp-sourcemaps resolves this by adding commenting paths to which source files your code originated from.

gulp-browser-sync

By leveraging BrowserSync, this plugin immediately refreshes an open browser which links to files just changed by gulp. This means you can code, compile, and see the results in real time. This takes a bit extra effort to set up, so be sure to check their documentation.

gulp-load-plugins

Normally when creating our gulpfile, we need to start off by requiring our plugins via something like this:

var gulp = require('gulp'),
    del = require('del'),
    concat = require('gulp-concat'),
    rename = require('gulp-rename'),
    uglify = require('gulp-uglify'),
    sass = require('gulp-sass'),
    watch = require('gulp-watch'),
    livereload = require('gulp-livereload'),
    minifyCss = require('gulp-minify-css'),
    autoprefixer = require('gulp-autoprefixer');

gulp-load-plugins instead checks your package.json for any Gulp plugins and immediately requires them, thus saving you a few precious minutes. The output instead looks like:

var $ = require('gulp-load-plugins')();

Building The Gulpfile

Now that we have all these dope plugins, we can finally build our gulpfile. Here's an example (without using gulp-load-plugins for now):

var gulp = require('gulp'),
    del = require('del'),
    concat = require('gulp-concat'),
    rename = require('gulp-rename'),
    uglify = require('gulp-uglify'),
    sass = require('gulp-sass'),
    watch = require('gulp-watch'),
    livereload = require('gulp-livereload'),
    minifyCss = require('gulp-minify-css'),
    autoprefixer = require('gulp-autoprefixer');

gulp.task('styles', function() {
    return gulp.src('src/sass/*.scss')
        .pipe(sass({outputStyle: 'expanded', unix_newlines: true, linefeed: "lf"}).on('error', sass.logError))
        .pipe(autoprefixer())
        .pipe(minifyCss({
            keepSpecialComments: 1
        }))
        .pipe(rename("theme.min.css"))
        .pipe(gulp.dest('./assets/css/'));
});


gulp.task('scripts', function() {
    return gulp.src(['src/js/plugin/*.js', 'src/js/base.js'])
        .pipe(uglify())
        .pipe(concat('theme.min.js'))
        .pipe(gulp.dest('assets/js'));
});


gulp.task('ghost_config', ['scripts'], function() {
    return gulp.src(['src/js/config.js', 'assets/js/theme.min.js'])
        .pipe(concat('theme.min.js'))
        .pipe(gulp.dest('assets/js'));
});


gulp.task('default', function() {
    gulp.start('styles', 'scripts', 'ghost_config', 'watch');
});


gulp.task('watch', function() {
    gulp.watch('src/sass/*.scss', ['styles']);
    gulp.watch('src/js/*.js', ['scripts', 'ghost_config']);
    livereload.listen();
    gulp.watch(['*']).on('change', livereload.changed);
});

Just by looking at the file itself, you may be able to dissect what's happening here. After we require our plugins, we define our tasks, which are essentially individual jobs consisting of one or more gulp plugins depending on how you've chained them.

Here's the general terminology to help clear things up:

  • gulp.task: Defines a task consisting of one of more plugin actions.
  • gulp.src:  Specifies the folder containing source files.
  • gulp.dest: Defines the folder to output compiled files to.
  • pipe(): Allows multiple events to be chained together in a single task.

Wrapping up

Once your file is ready to go, simply run the grunt command in your project directory. You should see Gulp output the status of each task you've set, as well as any errors which may have occurred.

In short, just use Gulp. The scientific community has come to a consensus that Gulp is objectively superior to its counterpart, Grunt. Ask Matt, he's a scientist.

Peace fam!

Author image
New York City Website
Product manager turned engineer with an ongoing identity crisis. Breaks everything before learning best practices. Completely normal and emotionally stable.

Product manager turned engineer with an ongoing identity crisis. Breaks everything before learning best practices. Completely normal and emotionally stable.