WordPress theme development using Gulp 4

Using Gulp 3 for many years, it’s been a while since I started thinking about refreshing my development workflow.

I didn’t… But why?

I tried Webpack

At least, I read the doc. The more you read it, the more you realize it will be very efficient with javascript applications, modern frameworks, but not great with WordPress development. By default, it will take all of your app files and bundle them in a single file. In a WordPress scenario, I want to target different groups of files (.scss, .js, …), process them differently, then place them wherever I want. Gulp is very good at this.

I think that with a lot patience and documentation reading, you could achieve that using Webpack. But Webpack is all about configuration, and I hate configuration.

What bothers me the most with modern workflows is the common huge amount of configuration. Call me a Boomer but I sometimes miss the days you could simply start from scratch with a PHP file: the only thing you need is a local server.

Anyway, the big difference between Gulp and Webpack is that using Gulp, you write functions, not configuration. Reading a Gulp file for the first time feels much more confortable than reading the (un)famous webpack.config.js.

Seriously, if you’re not a Webpack pro, try to read this or this and tell me “Yeah loved it I definitely take that option it looks so simple” 🙄
(and we are speaking of first Google results for wordpress development using webpack)

I tried NPM

I told to myself “Hey, you’re using Gulp, which needs NPM to run, why wouldn’t do the same using NPM only?

So I read this article by Kevin Bauman. It was perfect, his configuration matches exactly what I’m looking for. Except it didn’t feel like an upgrade to me. Maybe I could get rid of Gulp, but I was losing readability. I mean, look at the full package.json file at the end. Does it looks clear to you? Not to me, not enough.

But I kept Gulp

Any attempts eventually ended the same way: “Why am I trying to be fancy, trying to follow the workflow trends, my gulpfile here already does everything I need.

Then I just rewrote my long-lived gulpfile so it could match its version 4 syntax. Here it is:

const gulp         = require('gulp'),
      sass         = require('gulp-sass'),
      postcss      = require('gulp-postcss'),
      autoprefixer = require('autoprefixer'),
      cssnano      = require('gulp-cssnano'),
      uglify       = require('gulp-uglify'),
      concat       = require('gulp-concat'),
      sourcemaps   = require('gulp-sourcemaps');

    
/**
 * Sources & destinations.
 */

const paths = {
    scss: {
        src: './assets/scss/**/*', // Will be used by `src()` and `watch()`.
        dest: './assets/dist/css/'      // Will be used by `dest()`.
    },
    js: {
        src: './assets/js/**/*.js', // Will be used by `src()` and `watch()`.
        dest: './assets/dist/js/'   // Will be used by `dest()`.
    }
};


/*
 * Processing & compiling styles.
 */

function styles()
{
    return gulp.src(paths.scss.src)              // Source files. Could be an array.
        .pipe(sourcemaps.init())                 // Init source maps.
        .pipe(sass().on('error', sass.logError)) // Compile scss/sass into css.
        .pipe(postcss([ autoprefixer() ]))       // Autoprefixing for browser compatibility.
        .pipe(concat('style.min.css'))           // Putting everything in a single file.
        .pipe(cssnano())                         // Minifying.
        .pipe(sourcemaps.write('./maps'))        // Writing source maps (relative to destination).
        .pipe(gulp.dest(paths.scss.dest));       // Sending compiled file to destination.
}


/*
 * Processing JS.
 */

function scripts()
{
    return gulp.src([                 // Source files.
        // './node_modules/...',
        paths.js.src
    ])
    .pipe(sourcemaps.init())          // Init source maps.
    .pipe(concat('scripts.min.js'))   // Putting everything in a single file.
    .pipe(uglify())                   // = renaming variables + minifying.
    .pipe(sourcemaps.write('./maps')) // Writing source maps (relative to destination).
    .pipe(gulp.dest(paths.js.dest));  // Sending compiled file to destination.
}


/*
 * Watch tasks.
 */

function watchAll()
{
    gulp.watch(paths.scss.src, gulp.series(styles));
    gulp.watch(paths.js.src, gulp.series(scripts));
}

exports.styles  = styles;
exports.scripts = scripts;
exports.build   = gulp.parallel(styles, scripts);
exports.default = watchAll;

Functions styles and scripts do similar things, but still it allows you to be specific if needed. We could add Babel transpilation in the scripts process.

The gulp.watch lines watch for changes in your source files, then run the related tasks. You could easily write more functions and add them into the process.

About writing source maps, I added (relative to destination) on purpose because it means in this case that they will go to my assets/dist/ folder, aka production.
If you’re not confortable with pushing maps files to production, I highly recommend you to read this article by Chris Coyier.

In case you’d like your maps to stay in development folder, you may have to do something like below, in order to keep correct paths, or maps won’t be accurate in your browser:

// Sending maps files to development folder.
...
.pipe(sourcemaps.mapSources(function(sourcePath, file) {
return '../../scss/' + sourcePath;
}))
.pipe(sourcemaps.write('../../scss/maps'))
...

The only new thing in this refreshed version is const paths, defining where are the source files and where they should go once compiled, so it is easier to reuse on another project/by another person. Compared to Webpack, it feels like it’s my only part of real configuration.

About browser-sync

One thing I didn’t include (yet) is Browsersync. With a few more line of code, it allows you to live-reload your browser(s) every time you update your source files, sparing you from manually reloading your browser to see the changes.
As I like to make changes in the Chrome dev tools to see their effects, I don’t mind not having live reload because I’m also a cmd+s freak and I would lose my changes if I havn’t moved them all to my source file, but I definitely could add brwoser-sync to the workflow and just get used to it.

That’s it!

I didn’t split the gulp file into smaller parts for this article, as I think comments are self-explanatory, but feel free to ask for it!

Hope this will help!