Nodejs: Optimize With Gulp and Brotli

Make a custom build pipeline for minifying and compressing your assets

Haseeb Anwar
Sep 14 · 7 min read
Image for post
Image for post

What you will get from this piece?

In this article, we’re going to build a server-rendered application in Nodejs by implementing:

  • A development environment where assets are minified and compressed in real-time.
  • A build process that can make distributable assets for deployment.

Setting up the Application:

Make a new directory, initialize npm, and install express and handlebars:

npm i express express-handlebars
app.js

Add some assets:

In order to minify and compress assets, we need assets. Let’s create a folder assets in the root of the project, and add some CSS and JS files. The app folder structure will look like this:

my-app
├── assets
│ └── css
│ └── styles.css
│ └── js
│ └── main.js
├── node_modules
├── views
│ └── main.hbs
├── app.js
├── package.json
└── package.lock.json
<link rel="stylesheet" href="/css/styles.min.css">
<script src="/js/main.min.js"></script>

Start with Gulp:

Gulp is a JavaScript toolkit that allows developers to automate web development workflows. It has many plugins to accommodate all your needs. Let’s start by installing gulp and necessary plugins for the minification of CSS and JS.

npm i -D gulp gulp-cli gulp-rename gulp-clean-css gulp-uglify-es
  • gulp-cli: Command Line Utility for Gulp
  • gulp-rename: A gulp plugin to rename files easily during the build process
  • gulp-clean-css: A gulp plugin to minify CSS using clean-css
  • gulp-uglify-es: A gulp plugin to minify JavaScript (es6 supported)

Make a Build Pipeline:

What we want from our pipeline is to take files from the assets directory, minify them and save them in a new directory dist by postfixing filenames as {filename}.min.{file_extenstion} . So if we have a CSS file in /assets/css/styles.css then the dist will contain /dist/css/styles.min.css .

const { src, dest, parallel, watch } = require('gulp');
const cleanCSS = require('gulp-clean-css');
const uglify = require('gulp-uglify-es').default;
const rename = require('gulp-rename');
const paths = {
css: {
src: 'assets/css/*.css',
dest: 'dist/css/',
},
js: {
src: 'assets/js/*.js',
dest: 'dist/js/',
},
};
function minifyAndCompressCSS() {
return src(paths.css.src)
.pipe(cleanCSS())
.pipe(rename({ extname: '.min.css' }))
.pipe(dest(paths.css.dest));
}
  1. After that, we are minifying CSS files by calling cleanCSS() plugin.
  2. Then we are changing the extension of the files to min.css
  3. Finally, we are saving minified files to the dist directory by using thedest() middleware of gulp.
function minifyAndCompressJS() {
return src(paths.js.src)
.pipe(uglify())
.pipe(rename({ extname: '.min.js' }))
.pipe(dest(paths.js.dest));
}

Watch for files:

We want our assets to be minified and compressed in real-time during development. Let’s create a task that watches our assets for changes and reflect changes in distributable assets.

function watchFiles() {
watch(
paths.css.src,
{ ignoreInitial: false },
minifyAndCompressCSS
);
watch(
paths.js.src,
{ ignoreInitial: false },
minifyAndCompressJS);
}
exports.watch = watchFiles;
exports.build = parallel(minifyAndCompressCSS, minifyAndCompressJS);
gulpfile.js (for minification only)

Automate the build process:

Now, we have created the tasks we need for our pipeline, lets make them work by defining some scripts in package.json. First, add two dependencies

npm i -D nodemon concurrently
  • concurrently: Allows to run multiple commands concurrently
"scripts": {
"start": "node app",
"dev": "concurrently \"nodemon app\" \"gulp watch\"",
"build": "gulp build"
},
  • dev: This script runs multiple commands with concurrently where nodemon app restarts the server when files are changed and gulp watch executes the watch task exported from gulpfile.js
  • build: This script can be used to make distributable assets on deployment or when you just want to make a build without running dev script.

It’s time to test:

Open up your command line and run npm run dev from the root of your project. When you run this command you will see that a new directory dist is added to your project with minified assets.

Add Compression:

Till now we have added minification to our assets which simply alters the text but compression reduces the size of the assets further by completely rewriting the binary code within a file. The compressed file will then be decompressed by the browser. All modern browsers support gzip and brotli for the decompression of assets. Brotli is considered to be the most efficient of them so will use this.

npm i -D gulp-brotli zlib
  • zlib: a software library used for data compression (we will use this library to provide some configuration options to gulp-brotli)
const gulpBrotli = require('gulp-brotli');
const zlib = require('zlib');
function minifyAndCompressCSS() {
return src(paths.css.src)
.pipe(cleanCSS())
.pipe(rename({ extname: '.min.css' }))
.pipe(gulpBrotli(brotliOptions()))
.pipe(rename({ extname: '.br' }))
.pipe(dest(paths.css.dest));
}
function brotliOptions() {
return {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]:
zlib.constants.BROTLI_MAX_QUALITY,
},
};
}
gulpfile.js

Serve Brotli compressed assets:

In order to serve Brotli compressed assets to the browser, we need to do some configuration.

/* serve Brotli compressed CSS files wheneve there is a request for .css file */app.get('*.css', (req, res, next) => {
req.url = req.url + '.br';
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'text/css; charset=utf-8');
next();
});
/* serve Brotli compressed JS files whenever there is a request for .js file */app.get('*.js', (req, res, next) => {
req.url = req.url + '.br';
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
next();
});

The Startup

Medium's largest active publication, followed by +704K people. Follow to join our community.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store