Transpile and minify Javascript, HTML and CSS using Gulp 4

This guide seeks to help out those trying to set up Gulp javascript transpilation and minification. Since minification is mostly beneficial on the front-end side of the web, this article describes how to set up basic HTML and CSS minifcation as well.

The resulting gulpfile is available here as a gist for those who want to get things up and running immediately, however I do recommend writing along with the article to make it stick.

Javascript transpilation

The dependencies we will need to get modern javascript transpiled.

  • Our most obvious one, Gulp version 4+
  • Using Browserify we will be able to bundle modules into a single file (a bundle).
  • To be able to use modern javascript in our browser we transpile our bundle into javascript understood by current and last-gen browsers, we will be using Babelify for this.
  • We need to use vinyl-source-stream to turn our bundle into something which gulp understands to be able to write it to a file.

Let’s intall these dependencies and write the basis of our gulpfile.

$ npm install --save-dev gulp browserify babelify vinyl-source-stream
const gulp = require("gulp");
const browserify = require("browserify");
const babelify = require("babelify");
const source = require("vinyl-source-stream");

// To prevent rewriting the source and build folder locations
const paths = {
	source: "./src",
	build: "./build"
};

// Let's write our task in a function to keep things clean
function javascriptBuild() {
	// Start by calling browserify with our entry pointing to our main javascript file
	return (
		browserify({
			entries: ["./src/scripts/main.js"]
		})
			// Bundle it all up!
			.bundle()
			// Source the bundle
			.pipe(source("bundle.js"))
			// Then write the resulting files to a folder
			.pipe(gulp.dest("./build/scripts"))
	);
}

// Expose the task, this allows us to call this task
// by running `$ gulp build' in the terminal
exports.build = javascriptBuild;

We did it! Our build task now transpiles and bundles our javascript, not too shabby. 

Javascript minification

Unfortunately the transpiled code is far too good looking, the world wide web appreciates performant, not pretty code. So we will be making an effort to uglify our transpiled code. Let’s take a look at our dependencies to make minification happen.

  • While vinyl-source-stream does a good job turning the bundle into a stream other plugins prefer to receive text in a buffer, we will use vinyl-buffer for this.
  • Quite simple, we pipe into gulp-uglify a buffer of pretty code, and out comes ugly code who would have guessed!
$ npm install --save-dev vinyl-buffer gulp-uglify
const gulp = require("gulp");
const browserify = require("browserify");
const babelify = require("babelify");
const source = require("vinyl-source-stream");
const buffer = require("vinyl-buffer");
const uglify = require("gulp-uglify");

function javascriptBuild() {
	return (
		browserify({
			entries: ["./src/scripts/main.js"]
		})
			.bundle()
			.pipe(source("bundle.js"))
			// Turn it into a buffer!
			.pipe(buffer())
			// And uglify
			.pipe(uglify())
			.pipe(gulp.dest("./build/scripts"))
	);
}

exports.build = javascriptBuild;

HTML minification

Okay, not bad. We set up javascript transpilation and minification, but I doubt you will be using minified code on the back-end. We can do better, on to HTML minification!

All we need is a single dependency, gulp-htmlmin it’s all in the name really. Its implementation is just as straightforward, don’t forget to edit the exposed task so both HTML and Javascript get minified!

$ npm install --save-dev gulp-htmlmin
const htmlmin = require("gulp-htmlmin");

// Write our html task in a seperate function
function htmlBuild() {
	return gulp
		.src("./src/*.html")
		.pipe(htmlmin())
		.pipe(gulp.dest("./build"));
}

// We have to change our exposed task, these functions can be ran in parallel as they do not depend on eachother.
// If your functions should run synchronously use gulp.series()
exports.build = gulp.parallel(javascriptBuild, htmlBuild);

CSS minification

Assuming you’re styling your website, you will have to minify your stylesheets as well.

  • The gulp-postcss package enables other packages to transform and modify our CSS files.
  • CSSNano is a PostCSS plugin used for minification, check out its documentation for more options and plugins to optimize its results with your project constraints in mind.

Again, we should keep in mind to edit our exposed task.

$ npm install --save-dev gulp-postcss cssnano
const postcss = require("gulp-postcss");
const cssnano = require("cssnano");

function cssBuild() {
	return gulp
		.src(`${paths.source}/styles/**/*.css`)
		.pipe(postcss([cssnano()]))
		.pipe(gulp.dest(`src/styles`));
}

exports.build = gulp.parallel(javascriptBuild, cssBuild, htmlBuild);

Your end result should be a better optimized website, at least all of your code. I recommend looking into compressing your images as they usually make up the bulk of the size on a webpage. Be sure to check back soon, I will be writing a quick guide to image compression using Gulp ASAP!

Keeping things tidy

Our tasks should work perfectly, but we are not cleaning after ourselves right now. As it happens during a project, some HTML and CSS source files get deleted or moved as it updates, but these tasks keep filling up the build folder (leaving old files if not overwritten).

We can write a task to remove the build folder before each build using the del package.

$ npm install --save-dev del
function cleanup() {
	// Simply execute del with the build folder path
	return del([paths.build]);
}

// We have to run the cleanup task first, after which we can run the build tasks 
exports.build = gulp.series(cleanup, gulp.parallel(javascriptBuild, htmlBuild, cssBuild));

Related articles