Eric Bergman-Terrell's Blog

Node.js / Express Programming Tip: How to Minify Web Content
September 19, 2015

In order to get the best performance out of your website, it's important to avoid sending bloated content to your website's visitors. This is especially true for visitors using mobile devices: bloated websites will not only be slow and unresponsive, they will tend to drain the battery faster than they should.

CSS and Javascript

This website had some CSS and Javascript that was not minified. In other words, the content was formatted for readability by the developer. For instance, while this javascript file was readable, thanks to the generous whitespace and long and meaningful variable names, its size was 368 bytes:

$(document).ready(function () {
    var offsettop = parseInt($("body").css("height"));
    window.scrollTo(0, offsettop);

    $("#TopButton").click(function () {
        window.scrollTo(0, 0);
    });

    $("#BottomButton").click(function () {
        var offsettop = parseInt($("body").css("height"));
        window.scrollTo(0, offsettop);
    })
});

Minified version:

$(document).ready(function(){var a=parseInt($("body").css("height"));window.scrollTo(0,a);$("#TopButton").click(function(){window.scrollTo(0,0)});$("#BottomButton").click(function(){var b=parseInt($("body").css("height"));window.scrollTo(0,b)})});

After minifying this file with yuicompressor the file size was reduced to 247 bytes, a savings of almost 33%. And I didn't have to sacrifice readability. I used a "File Watcher" in WebStorm to automatically update a separate, minified version of the file every time the original file is updated. I did the same thing with the CSS files, with similar results.

HTML

This website's HTML content is generated with EJS templates. Like the Javascript and CSS files, these templates were formatted for readability, not to conserve the user's bandwidth. I could have minified HTML content the same way I minified Javascript and CSS content, but I chose a different approach. Instead, I wrote a middleware function that intercepts the bloated HTML responses and minifies the HTML using html-minifier. You'll notice that the middleware function makes sure that the content type is HTML before doing the HTML-specific minification. Also, it's important to catch any errors thrown during the minification process. Some HTML may render properly in the user's brower, but may contain errors that prevent it from being successfully minified.

requestHook.js:

...
var htmlMinifier = require('html-minifier');
...

function isHtml(text) {
    var prefix = "<!DOCTYPE html>";

    return text.length >= prefix.length && text.substring(0, prefix.length) === prefix;
}

exports.requestHook = function(req, res, next) {
    if (req.method === 'GET' || req.method === 'POST') {
...
        var oldSend = res.send;

        res.send = function(data) {
            if (data != null) {
                var htmlText = data.toString();

                if (htmlText.length > 0 && isHtml(htmlText)) {
                    try {
                        data = htmlMinifier.minify(htmlText, {
                            removeComments: true,
                            collapseWhitespace: true
                        });
                    }
                    catch(error) {
                        global.logger.error('requestHook: cannot minify html for ' + req.url);
                        global.logger.error(error);
                    }
                }
            }

            oldSend.apply(res, [data]);
        }
    }

...
        next();
...
};

app.js:

...
var requestHook = require('./libs/requestHook');
...

app.use(requestHook.requestHook);
...

I have mixed feelings about this minification solution for HTML content. On the plus side it's highly effective, it minifies the EJS templates, as well as any data dynamically inserted into those templates. On the minus side, it must be fairly CPU intensive. Perhaps a better solution would be a mechanism similar to the one I used for CSS and Javascript content, that would work for EJS templates.

Compression

Even after your Javascript, CSS, and HTML is minified, it's possible to conserve additional bandwidth by compression. I used the compression module. I chose to specify the threshold (i.e. the minimum size file that will be compressed).

app.js:

...
var compression = require('compression');
...

app.use(compression({
    threshold: config.compressionThreshold
}));

compression

minify your web content for speed
Minify and compress your web content for maximal speed!

Keywords: Node.js, node, Express, Minification, Minify, yuicompressor, Javascript, CSS, stylesheets, bandwidth, EJS, Content Type, compression, gzip, content-type, HTML

Reader Comments

Comment on this Blog Post

Recent Posts

TitleDate
Java Programming Tip: SWT Photo Frame ProgramOctober 31, 2016
Vault 3 (Desktop) Version 1.63 ReleasedSeptember 9, 2016
"Compliance with Court Orders Act of 2016"April 9, 2016
Disable "Visual Voicemail" on Android / T-MobileJanuary 17, 2016
IPv6 HumorDecember 10, 2015
Java Programming Tip: Specify the JVM time zoneDecember 7, 2015
Node.js / Express Programming Tip: Detect and Fix Memory LeaksOctober 27, 2015