A modern JavaScript and SASS-y WordPress development workflow with Gulp 4

Reading Time: 7 minutes

If you’re looking to get started using SASS and modern JavaScript in your WordPress projects, be it theme or plugin, you’re going to need to something to handle the compiling.

There are plenty of options out there. You have CodeKit for a more user focused interface, Webpack is the new hotness taking over the world, and Grunt is the old standard. This is article is going to focus on using Gulp to handle the task-running and compiling of your development workflow.

What is Gulp

Gulp is a JavaScript based task-runner built on Node.js for automating development workflows.

In addition to actions like compiling SASS, you can compile modern JavaScript into browser-compatible JavaScript with Babel, minify and concatenate files, run tests, refresh your browser when files are changed, and much more.

A lot of these actions are performed by the large library of plugins available for Gulp. But you can do anything you’d like with vanilla JavaScript and Node modules inside your gulpfile which we’ll touch on in a bit.

First we need to get Gulp installed.

Installing Node.js

Before getting Gulp installed you’ll need Node.js, npm, and npx installed. If you’re not sure you have those installed it is easy enough to check. Pop open your terminal and run the following commands.

node --version
// returns node version

npm --version
// returns npm version

npx --version
// returns npx version

Each of these commands should return something along the lines of 10.15.1 depending on the version you have.

If you don’t have them installed go ahead and install Node.js and it should take care of it all.

Sidebar: Managing Node Versions
If you’re getting Node.js installed now may be a good time to take a look at installing Node Version Manager (nvm) as well. nvm allows you to switch between versions of Node.js on your system which is very useful if you end up working on a legacy project with packages that haven’t been updated to work with the latest version of Node.js.

Getting setup with Gulp

First, you’ll need to install the gulp command line utility. Open up your terminal and run npm install --global gulp-cli.

Next, you’ll either need to navigate to a directory of an existing project or create a new directory. Using a WordPress theme as an example (though this workflow works just as well for plugins) you would want to navigate into your theme directory folder. Depending on where your files are located on your system that could be something like:

cd ~/sites/my-site/wp-content/themes/my-theme

Once inside the desired directory in your terminal you’ll need to create a package.json file. This is where the packages your project depends on are stored. The file is created by running the following command:

npm init

This will take you through a series of prompts for giving your project a name, description, and more.

Once this is complete the first package we’ll want to save into our devDependencies is gulp itself. To do that we run:

npm install --save-dev gulp

This format will get familiar as it’s how you save all your packages for development purposes.

Getting Gulp to Do Stuff

Now that we have gulp installed we need it to do stuff to automate our workflow.

Poke Watching GIF - Find & Share on GIPHY

Create a gulpfile

How we get gulp to do stuff is by creating a gulpfile. A gulpfile is simply a JavaScript file in our project that we can configure our automations in. So we just need to create a gulpfile.js in the project then start adding tasks.

Sidebar: Troubleshooting Gulp Installation
If you run into issues getting Gulp installed on your system check out the guides available on Gulp.js.

Installing packages

Before we can do cool stuff like automatically inject our CSS into the browser without reloading the page we need to add packages.

gulp-sass

This package will allow compiling of SASS or SCSS into a CSS file.

npm install node-sass gulp-sass --save-dev

More on this package

gulp-csso

The gulp-csso package lets you minify and optimize CSS.

 npm install gulp-csso --save-dev

More on this package

gulp-babel

The gulp-babel packages gives the ability to write modern (ES6+) JavaScript and compile it into browser compatible JavaScript.

npm install --save-dev gulp-babel @babel/core @babel/preset-env

More on this package

gulp-concat

The gulp-concat package will be used to concatenate JavaScript files into a single build file.

npm install --save-dev gulp-concat

browser-sync

browser-sync lets you watch files for changes to reload the browser and inject CSS into the browser without a reload.

npm install browser-sync gulp --save-dev

After running all of those commands you can check out your package.json to see all of those packages included. If you were then to copy your package.json and gulpfile.js to new projects you would only need to run npm install to get up and running.

Sidebar: The node_modules directory
You may notice a new directory in your project folder named node_modules. If you track your project with version control like git you’ll want to include the package.json and gulpfile.js, but do not track the node_modules directory. To do that you’ll add node_modules to your .gitignore. Why? Because this stores all of the packages your project is dependent on and can get rather large. Instead just run npm install when you’re getting started for the first time.

Setting up a gulpfile

Now that we have all the packages installed we want to do something with them. That’s where the gulpfile comes into play.

In its most basic form a gulpfile can consist of a simple default function that runs when you type gulp into terminal within the project directory.

function defaultTask(cb) {
  // place code for your default task here
  cb();
}

exports.default = defaultTask

What does that function do? Nothing. But there are a few key takeaways when looking at that code.

First, you’re defining a function called defaultTask in a standard JavaScript format.

Next, you’re exporting the function as a public task named default. Public tasks can be called directly by running gulp default in terminal. We’ll do this with our sass command so if we need to we could just run the SASS compilation part of our gulpfile without doing everything else.

We’re not going to use that so feel free to delete it. And we’ll start from the top of our gulpfile and work our way down.

Requiring packages

In order to use the packages we’ll first reference them as variables to easily make use of the functionality they provide.

const { src, dest, watch } = require('gulp');
const sass = require('gulp-sass');
const minifyCSS = require('gulp-csso');
const babel = require('gulp-babel');
const concat = require('gulp-concat');
const browserSync = require('browser-sync').create();

On the first line we’re destructuring the src, dest, and watch methods out of gulp API. src essentially lets you make a reference to the source file and dest lets you write a file to a destination. watch allows for watching files. For a more in depth look, check out the Gulp API.

For the rest of the packages we’re assigning them to a const.

Sidebar: gulp.task
You’ll see a lot of samples online using gulp.task for defining gulp tasks. And that works just as well. This guide is based on the current Gulpjs.com Getting Started guide and uses a similar destructuring method. If you prefer the former you could use const gulp = require('gulp'); as your first line. Then rather than call src() you could call gulp.src().

Building gulp tasks

Now let’s create our first task that will compile our sass, minify the css output, output the file to the project, and inject it into the browser.

function css() {
    return src('./sass/*.scss', { sourcemaps: true })
        .pipe(sass())
        .pipe(minifyCSS())
        .pipe(dest('./'), { sourcemaps: true })
        .pipe(browserSync.stream());
}

The src call’s first argument looks for any files ending in .scss inside the sass directory of our project and generates an inline sourcemap. For external sourcemaps pass a path instead of true. As a side note you probably don’t want to inline your sourcemaps for production.

Our next line uses the pipe() method of gulp to essentially manage the flow of data throughout gulp. Inside this pipe() call we’re calling the sass() function to compile our sass.

Then we pass that along to our minifyCSS() call that minifies the CSS.

Next up we use destination that writes the file to the root of our project ('./') again with an inline sourcemap. In this case the file name comes from our base SASS file. Typically style.scss in the root of the sass directory.

Finally we pass it to browserSync.stream() that injects the CSS into our browser. Given a proper browserSync configuration which we’ll get into shortly.

First let’s create function for handling our JavaScript to compile it with Babel, concatenate multiple files, and save it to a /js/min directory.

function js() {
    return src('./js/*.js', { sourcemaps: true })
        .pipe(babel({
            presets: ['@babel/env']
        }))
        .pipe(concat('build.min.js'))
        .pipe(dest('./js/min', { sourcemaps: true }));
}

The core of this function is the same as our css() function. Though the babel() function has a bit extra. I won’t dive deep into presets: ['@babel/env'] line. But this can give you control over the browser compatibility you need for your project with JavaScript.

@babel/preset-env is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller!

Babel.js Docs

Now with those tasks setup we’ll move into our final task. Setting up browserSync.

function browser() {
    browserSync.init({
        proxy: 'domain.local',
        files: [
            './**/*.php'
        ]
    });

    watch('./sass/**/*.scss', css);
    watch('./js/*.js', js).on('change', browserSync.reload);
}

The first bit of code initializes Browsersync. The first option we hit is the proxy. Since you’ll typically be doing WordPress development on a local server environment you’ll want to set this to the domain for the site.

The next option is files to watch. Here I’m watching any file ending in .php inside the root and any sub-directories. This is very useful if you have a templates directory in the root of your WordPress install.

CSS Tricks has a great guide on Globs with Gulp.

The next part of our browser() function is our watch() calls. watch() was one of the methods we pulled from gulp earlier and it lets us watch files for changes and call a function on them.

watch('./sass/**/*.scss', css); is watching our SASS files for changes and calling our css() function. Which as you recall ends with browserSync.stream() which injects our CSS.

watch('./js/**/*.js', js).on('change', browserSync.reload); watches for changes to files inside a js directory and calls the js() function. Then it has a little bit extra watching the change event and calls a browserSync.reload manually.

Exporting Gulp Tasks

Now to wrap up this whole thing we need to export our default tasks and anything else we may want to call publicly.

exports.css = css;
exports.js = js;
exports.default = browser;

On the first line exports.css = css creates a public function named css that is equal to the css() function. So we can run gulp css from terminal and perform just the css() function.

Line 2 is the same but with the js() function.

Line 3 exports our default task as the browser() function. That means that when we run just gulp in our terminal it runs the browser() function which starts Browsersync and watches our CSS and JS files.

Wrapping Up

That’s it. Now you can start using SASS and modern JavaScript in your WordPress development workflow. Here’s the whole gulpfile.js thrown together in Gist form.

Further Reading

Gulp for Beginners | CSS-Tricks
Gulpjs.com Docs
Browsersync + Gulp.js

Pin It on Pinterest