Javascript minification patterns: Structuring for maximum compression

{2 Comments}

When it comes to JavaScript compressing and minification, I’m sure that most of us out there take it for granted and really don’t think too much about how the minifier we are using actual works or what it can actually minify. It turns out the actual structure of our code can have a major impact on the amount of minificaiton can actually perform.

The golden rule of most minifiers is to start by compressing the name of any non public variables. The problem  is that most of us don’t realize exactly what is and what isn’t public when it comes to JavaScript. Fortunately, there are some common patterns and practices we can use to help minifiers do their job and get the most out of the process.

Structuring for maximum compression
Structuring for maximum compression

Lets have a look at the following very contrived samples:

Sample 1

var pubsub = {};

//Support
pubsub.supportMethod1 = function () { /*...*/; };
pubsub.supportMethod2 = function () { /*...*/; };
pubsub.supportMethod3 = function () { /*...*/; };

//Main
pubsub.publish = function (message, data) { /*...*/; };
pubsub.subscribe = function (message, func) { /*...*/; };
pubsub.unsubscribe = function (token) { /*...*/; };

the end result cannot be nearly as compressed as if we were to restructure our code into a more module design. The following shows how we might go able restructuring our code:

Sample 2

var pubsub = (function () {
    var //Support
        supportMethod1 = function () { /*...*/; },
        supportMethod2 = function () { /*...*/; },
        supportMethod3 = function () { /*...*/; },

        //Main
        publish = function (message, data) { /*...*/; },
        subscribe = function (message, func) { /*...*/; },
        unsubscribe = function (token) { /*...*/; };

    return {
        publish : publish,
        subscribe : subscribe,
        unsubscribe : unsubscribe
    };
}())

This altered code is very different to the first sample not only because it uses a module design patterns but this structure has the by product of protecting the variables.

This is a critical distinction as it means that minifiers can compress all variables except those that you are explicitly choosing to make public. This is possible with the first pattern but in my experience most developers writing JavaScript aren’t as conscious about this as they should be and in the end it results in code that is more bloated than it needs to be – even though its minified.

To show just what the difference can be look at the results when using Google’s Closure Compiler:

Sample 1

Original Size: 351 bytes (152 bytes gzipped)
Compiled Size: 166 bytes (91 bytes gzipped)
Saved 52.71% off the original size (40.13% off the gzipped size

var pubsub={supportMethod1:function(){},supportMethod2:function(){},supportMethod3:function(){},publish:function(){},subscribe:function(){},unsubscribe:function(){}};

Sample 2

Original Size: 405 bytes (180 bytes gzipped)
Compiled Size: 98 bytes (76 bytes gzipped)
Saved 75.80% off the original size (57.78% off the gzipped size)

pubsub=function(){return{publish:function(){},subscribe:function(){},unsubscribe:function(){}}}();

NOTE! The example I have provided is very trivial and one could argue that when these function have code, the saving in percentage terms wouldn’t be anywhere near as much. But in my experience since I started learning more about how JavaScript scoping works (what is public and hence what a minifier can’t compress) and making sure my scoping was correct, I started seeing:

  • More than decent reduction in file size as it turns out very few variables need to be public (in some cases none – meaning all variable names can be reduced)
  • I could understand my code better as I wasn’t choosing shorter names in an effort to help the minifier to its job
  • Lastly the quality of my code increased dramatically as it turns out the Module Pattern when implemented in JavaScript is fantastic way of of writing “good” JavaScript – which is one of the holy grails of web development

Best of luck!

UPDATE:

As @lordeagle pointed out, you can even take this further by assigning the values of statements that contain reserved words to variables. For instance, if you have a method that has multiple uses of “this”, at the start of the function you could assign this to a variable.

2 Comments…

 Share your views
  1. Nice article, but as always there are other trade-offs. There is also a memory / performance trade-off by writing privates instead of using prototypes. Every instance of PubSub is going to have to evaluate the code as opposed to only defining the functions once on the prototype. Each instance will get its own copy of the function objects since they are not being shared on the prototype. While I am not certain, I also think js engines can perform more optimizations when objects extend prototypes as opposed to tracking private closures all the time.

    The compression issue becomes very clear once I started using coffeescript since its so natural to define prototype functions and public instance members.

  2. @Adam Thanks for the comment and I should have pointed thins out more. In the “Sample 2″ I provided you will see that the last line has “}())” the most important part being the “()”.

    This means that as the browser initial evaluates this function, it will execute the function. Meaning the results of the function (in this case the json object containing the “function pointers”) are assigned to pubsub.

    Hence in this case, by executing that function in the way that I am, its still functionaly identical to the first sample and there is no perf cost each time you want to use pubsub. Does this make sense?

Leave a Comment

Your email address will not be published.

{ 1 Trackback }

  1. The Morning Brew - Chris Alcock » The Morning Brew #965 (Pingback)