I’m building a basic Express-based Node app. I wanted a simple build system to rebuild/reload everything with BrowserSync when I made a change to my source files:

  • change source CSS? It runs postcss, processes it and spits it into the ./public folder
  • change front-end JS? It concatenates in and spits it into the ./public folder
  • change a handlebars template in my ./Views? It should restart the Node/Express app and reload the browser

No good examples

Scouring the net for examples of how to do this I was stumped in two ways; I’d never done this before so wasn’t sure what I needed, and secondly, there didn’t seem to be any straightforward examples of how to achieve this with Express in the mix.

Perhaps scripts would have been the more straightforward option but I opted for Gulp.

I spent a few hours trying to get a basic build system running last night and in desperation turned to Twitter. Thankfully I had my direction validated by Mr Buckler so I just had to figure out how to get it all working.

The solution I ended up with (using gulp-nodemon)

The “js” and “css” tasks were very straightforward, although I had to define them as a task rather than write them as a function for them to play happily with Nodemon.

The key thing to figure out was the gulp-nodemon plugin. Second key thing was getting browserSync to proxy to the right place.

So, my Express app was configured to use port 3000:

app.listen(3000, () => {
    console.log(`listening on ${chalk.green("3000")}`);
});

So I set that as the browserSync proxy and actually viewed my work at http://localhost:7000/. Here’s the full function:

function serve(done) {
    server.init(null, {
        proxy: "localhost:3000",
        open: false,
        files: ["public/**/*.*"],
        port: 7000,
    });
    done();
}

Configuring gulp-nodemon

Then, the main work was in figuring out how to get nodemon configured. Fairly straightforward is setting your script key. This is the entry point for your app. For me, it was the inventively titled `app.js’!

Turns out that gulp-nodemon has it’s own watch functionality built in. Set the extensions you are interested in with the ext key and it will do its thing when a file changes.

Just be sure to exclude your output files/folders or it will do things twice; once when you change the source file and again when it gets rewritten in the destination. You do that by adding stuff into the array for the ignore key.

Full gulpfile.js

Anyway, future self and copy and paste fiends, here is the full Gulpfile I ended up with:

var gulp = require("gulp");
var nodemon = require("gulp-nodemon");
var concat = require("gulp-concat");
var postcss = require("gulp-postcss");
var cssnano = require("cssnano");
var notify = require("gulp-notify");
var postcssMixins = require("postcss-mixins");
var simplevars = require("postcss-simple-vars")();
var autoprefixer = require("autoprefixer");
var browserSync = require("browser-sync");
var postcsseasyimport = require("postcss-import");
var postcssColorFunction = require("postcss-color-function");
var assets = require("postcss-assets");
var nested = require("postcss-nested");

const server = browserSync.create();

gulp.task("css", function (done) {
    var processors = [
        postcsseasyimport(),
        postcssMixins,
        simplevars,
        nested,
        assets({
            relative: true,
        }),
        postcssColorFunction(),
        autoprefixer(),
        cssnano(),
    ];

    gulp.src("./preCSS/styles.css")
        .pipe(postcss(processors))
        .pipe(gulp.dest("./public"))
        .pipe(notify("Boom! Up in yo CSS face!!"));
    done();
});

function serve(done) {
    server.init(null, {
        proxy: "localhost:3000",
        open: false,
        files: ["public/**/*.*"],
        port: 7000,
    });
    done();
}

gulp.task("js", function (done) {
    gulp.src("preJS/*.js", { sourcemaps: true })
        .pipe(concat("interface.js"))
        .pipe(gulp.dest("./public"))
        .pipe(notify("Boom! Up in yo JS face!!"));
    done();
});

function nodeDev(done) {
    var stream = nodemon({
        script: "app.js",
        ignore: ["gulpfile.js", "node_modules/**", "public/**"],
        tasks: ["css", "js"],
        ext: "js css html",
        env: { NODE_ENV: "development" },
        done: done,
    });
    stream
        .on("restart", function () {
            console.log("restarted!");
            server.reload();
        })
        .on("crash", function () {
            console.error("Application has crashed!\n");
            stream.emit("restart", 10); // restart the server in 10 seconds
        });
}

const dev = gulp.series(serve, nodeDev);
exports.default = dev;


Summary

I hope that saves someone a few hours in future or at least puts them on a decent path.

Probably not the sleekest solution but I can now get on with trying to build something instead of configure my build tools!

If anyone has something more effective, I’m all ears!