From Drush to Gulp

I recently decided to set up a blog to write about things web-related, but instead of using the familiar Drupal and Omega theme, I opted for Wordpress. I am used to writing CSS with Sass compiled with Drush, but Wordpress didn’t seem to have support for Drush and I also wanted to try something new. Enter Gulp.

The source code for this post can be found on Github.

When developing CSS for Drupal, Drush is a great tool. One of my favorite features is being able to clear Drupal’s cache from the command line (which, if you have ever used Drupal, you will need to do frequently). However, there are a couple issues with Drush that have been nagging at me since I have started using it, the biggest one being that when the number of .scss files grew (not including partials), so does the compilation time. Keep in mind we’re talking on the order of seconds, but when each file takes 1 or 2 seconds to compile, it can add up pretty quickly and significantly slow down development.

It wasn’t difficult to find a replacement for compiling Sass with Drush in 2017. There have already been a few players out there, but after a bit of research, I decided on Gulp. Gulp is a task runner used for automating tasks such as compilation, minification, and testing and has been making waves in the development community for a couple years now due to its ease of use and flexibility. I’m a bit late to the game, but boy has it made my life better.

The first thing I needed to do was install Gulp through npm. This can be done through npm install or package.json, it doesn’t really matter which method is used. I will not be covering npm or package.json in this article.

Once installed, I wrote a very simple gulpfile.js to test that everything was working OK.

var gulp = require('gulp');

gulp.task('default', function() {
  // do nothing
});

Then in the command line:

$ gulp
[01:17:04] Using gulpfile /var/www/gulp-sass-demo/gulpfile.js
[01:17:04] Starting 'default'...
[01:17:04] Finished 'default' after 125 μs

Great, everything seemed to be working the way it should.

Gulp runs tasks to perform operations. I created a default task above, but I could create a new one and call it whatever I want.

Let’s get started with compiling Sass. First, I installed gulp-sass from npm and included it in the gulpfile:

var sass = require('gulp-sass');

Next, I created a new task that compiles Sass into CSS:

gulp.task('sass', function() {
  gulp.src('sass/**/*.scss')
    .pipe(sass())
    .pipe(gulp.dest('css'));
});

Now I needed a few files to test the Sass features. I created partials _variables.scss and _abstractions.scss and the main styles file main.scss for this test:

_variables.scss

$maxWidth: 640px;
$blockColor: blue;
$hoverBlockColor: purple;

_abstractions.scss

%block-style {
  height: 100px;
  width: 100px;
  border: 2px solid orange;
  background: $blockColor;
  &:hover {
    background: $hoverBlockColor;
  }
}

@mixin border-radius($radius) {
  border-radius: $radius;
}

main.scss

@import 'variables.scss';
@import 'abstractions.scss';

.container {
  display: flex;
  max-width: $maxWidth;
}

.block {
  flex: 1 1 auto;
  @extend %block-style;
}

.block-1, .block-4 {
  @include border-radius(10px);
}

Then I ran the new Gulp task:

$ gulp sass
[01:30:49] Using gulpfile /var/www/gulp-sass-demo/gulpfile.js
[01:30:49] Starting 'sass'...
[01:30:49] Finished 'sass' after 18 ms

Checking the css folder, the newly-created main.css file contained the following:

.block {
  height: 100px;
  width: 100px;
  border: 2px solid orange;
  background: blue; }
  .block:hover {
    background: purple; }

.container {
  display: flex;
  max-width: 640px; }

.block {
  flex: 1 1 auto; }

.block-1, .block-4 {
  border-radius: 10px; }

Great, it looks like it covers all the features but autocompile. Not a problem though, Gulp also has us covered with this. I can get Gulp to watch my sass folder while I work with a new task within my gulpfile:

gulp.task('watch:sass', function() {
  gulp.watch('sass/**/*.scss', ['sass']);
});

I named my task ‘watch:sass’ to remind me that this watch task runs the sass task, but you can name it whatever you like. If you have multiple watch tasks, this would be a good way to name them so you don’t get confused. I started the watch task with:

$ gulp watch:sass
[01:33:09] Using gulpfile /var/www/gulp-sass-demo/gulpfile.js
[01:33:09] Starting 'watch:sass'...
[01:33:09] Finished 'watch:sass' after 20 ms

With the watch task running, when I save any .scss file within my sass folder, Gulp will automatically run the sass task and compile my .scss files into CSS:

[01:33:27] Starting 'sass'...
[01:33:27] Finished 'sass' after 19 ms

Perfect, this basically covers all the features I was looking for with a new development tool. But if things were this easy, I wouldn’t be writing about this.

If you are like me and break up your Sass files into many partials and folders, you won’t want an import statement for each partial. For me, a basic sass directory for a project looks something like this:

sass/
  abstractions/
    _mixins.scss
    _placeholders.scss
  base/
    _media.scss
    _page.scss
    _typography.scss
  components/
    _footer.scss
    _header.scss
    _navigation.scss
    _search.scss
  variables/
    _colors.scss
    _grids.scss
    _typography.scss
  styles.scss

You can see that if I started adding more partials, I would have to add the import statement to each .scss file that would need it, and this could get quite lengthy. If I also forgot to add the import line, things wouldn’t work the way I would expect.

With Drush, a few lines would take care of this:

@import 'variables/**/*';
@import 'abstractions/**/*';
@import 'base/**/*';
@import 'components/**/*';

But if I tried to compile this with Gulp, I get a nasty error in the command line. I also couldn’t import compass and breakpoint, which I use in practically every project.

To solve this, I installed a few more plugins: node-sass-globbing, compass-mixins, and breakpoint-sass. I included node-sass-globbing into the gulpfile and created a sass_config variable:

var importer = require('node-sass-globbing');

var sass_config = {
  style: 'expanded',
  importer: importer,
  includePaths: [
    'node_modules/breakpoint-sass/stylesheets/',
    'node_modules/compass-mixins/lib/'
  ]
};

Then I passed sass_configs into the sass() function:

gulp.task('sass', function() {
  gulp.src('sass/**/*.scss')
    .pipe(sass(sass_config))
    .pipe(gulp.dest('css'));
});

When I compiled this again with Gulp, I get a clean compilation:

$ gulp sass
[00:20:49] Using gulpfile /var/www/test.blog.paulmkim.ca/public_html/gulpfile.js
[00:20:49] Starting 'sass'...
[00:20:49] Finished 'sass' after 20 ms

Hurray! With this, I have all the features I was looking for with Drush in Gulp. Gulp also compiles significantly faster than Drush, especially with multiple .scss files. But Gulp has many more capabilities than just mimicking the Sass-compiling capabilities of Drush.

One small annoyance I found with Gulp is that when watching a folder, if Gulp wasn’t able to compile any file due to an error, such as syntax or missing dependencies, Gulp would complain and quit the task. However, this was easily fixed with the gulp-plumber plugin. I also added other plugins for browser prefixes, minification, and more. To do this, I installed and included the following into my gulpfile:

var plumber = require('gulp-plumber'),
    util = require('gulp-util'),
    autoprefixer = require('gulp-autoprefixer'),
    cleancss = require('gulp-clean-css'),
    rename = require('gulp-rename'),
    log = util.log;

Then I added them to the tasks I created:

gulp.task('sass', function() {
  log('Generate CSS files ' + (new Date()).toString());
  gulp.src('sass/**/*.scss')
    .pipe(plumber())
    .pipe(sass(sass_config))
    .pipe(autoprefixer({browsers: ['last 2 versions', 'safari 5', 'ie 9']}))
    .pipe(gulp.dest('css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(cleancss())
    .pipe(gulp.dest('css'));
});

gulp.task('watch:sass', function() {
  log('Watching scss files for modifications');
  gulp.watch('sass/**/*.scss', ['sass']);
});

This does a number of helpful things:

  • gulp-util gives me a useful tool to log a description of each action and task that is being performed, which can be very handy when running complicated tasks.
  • If any .scss file isn’t able to compile for any reason, gulp-plumber will log the error in the command line and prevent the task from breaking. This is very convenient when performing a watch task.
  • gulp-autoprefixer, as the name implies, prefixes styles based on the browser requirements provided so I can write plain CSS and not worry about browser prefixes.
  • gulp-clean-css tidies and minifies the compiled css code.

After working with Gulp for a day, it’s safe to say that it is a significant upgrade from my previous setup. I love how it has improved my Sass development process with its modularity and simplicity. Unless something considerably better comes along, I may be sticking with this one for a while.