JavaScript Minification Part II

by Nicholas C. Zakas

11 Reader Comments

Back to the Article
  1. For the most part these suggestions are all quite good.  I would personally be hesitant about aliasing some of the builtin global variables (such as document) though. Whilst it may have a benefit in the size of the minified script, it could also defeat developers who are searching the source code, expecting to find “that document.getElementById” call they were looking to work on.  Unless they know that document is regularly aliased and what it is aliased to, this practice could make their job harder (the job of their search tools at least). Also, it feels counter-intuitive to me.  You would be purposely introducing non-standard names for the globals.  I would expect this to add to the (time) cost of adding new developers to the project as they are forced to cope with using new names for well-known/commonly-used variables. From my own (server-side) experience - I once changed a common local variable that was “standard to me” in projects I work on.  For months I caught myself instinctively mis-typing “db.CreateCommand()” where I meant to type “Connection.CreateCommand()”. Perhaps I’m too shielded from the world of .js these days, I spend the vast majority of my time in serverside logic where the size of the source files doesn’t matter anywhere near as much but I certainly wouldn’t ever want to be futzing with the names of my builtins there. Also - on the “single return point” issue, I always use a single return point regardless (and if I am returning anything, the variable I will be returning is always named “output”).  It makes code so much more readable and easy to follow if you can be 100% certain that - as long as no exception is raised - execution begins at the start and will continue to the end of every method.
    Copy & paste the code below to embed this comment.
  2. Not creating lots of global variables, and structured code without eval (evil)  in general is a good idea. But I don’t like the idea of having obfuscated code in production. First of all, I don’t like having to think about code that might not be compatible with the minifier you’re using. I don’t like extra restrictions, and I don’t want to think about them while coding, and I don’t want to stress about differences between production and a live environment. Secondly, even though at the company I work at, we test our code quite a lot, there are always minor bugs that show up in production because of unforeseen combinations of factors. They should’ve been killed in production, but in practice they aren’t. It’s really useful if the code is actually readable so debugging is faster and easier. With gzip and relatively fast internet, the amount of code saved is that minor that I conclude there’s not enough reason to minify. Unless you’re using a library that has proven to work as a minified version, like jQuery or Prototype.
    Copy & paste the code below to embed this comment.
  3. @craigfowler - I’ve been aliasing globals for a few years now, and have never run into developer confusion over this (provided that the variables names are easy to figure out, i.e. var doc = document, win = window;). The cognitive overhead of developers adapting to this is trivial, so I wouldn’t worry too much about that. @Blaise - This is technically not obfuscated code, it’s minified code. Obfuscated code is purposely hard for someone to understand and typically has some level of indirection. In this case, it’s just variable replacement and stripping of white space. The reason I recommend YUI Compressor over Closure Compiler is that the YUI Compressor goes through great pains to make sure that it’s *not* changing your code, it’s only making small optimizations that ultimately add up. I’ve never run into a production problem that was caused by the minification process. @atk If you’re more comfortable with line breaks remaining, or without variable replacement, there are “options”:http://developer.yahoo.com/yui/compressor/ for those. Also, if you’re really in a pickle and need to debug minified code in production, you can use the technique I described “here”:http://www.yuiblog.com/blog/2008/06/27/fiddler/ .
    Copy & paste the code below to embed this comment.
  4. @blaise and @atk: Remember, you should never have to look at/debug your minified code.  If you need to fix a bug then you fix it in your development source code (laid out by your organisation’s standards, full of useful documentation and comments and the like) and then re-minify it.  If a new developer comes into the project then you give them access to that source code, not just the minified script. The best possible solution of course is to make the minifcation step part of your automated build procedure (you’re using an automated build procedure right?).  That way if you need to do anything, you don’t just start hacking at the production code.  Instead you work with the development copy and build it into a new production copy.  This also works well if your are using a version control system ‘properly’: Branch » fix » build » test » merge. I like to think of minified JavaScript as I think of compiled binary executables and libraries.  It’s not meant to be human-readable.  If I want to change a binary then I edit the source code and rebuild/recompile to create a new binary.  It’s the same with minified js.
    Copy & paste the code below to embed this comment.
  5. The if..elseif example could be reduced further from 133 to 95 bytes by replacing the elseifs with a ternary structure: function getValueFor(data){
      return firstCondition(data)
      ?1
      :secondCondition(data)
        ?2
        :thirdCondition(data)
          ?3
          :4;
    }
    Copy & paste the code below to embed this comment.
  6. I like the content of this article and believe that squeezing every available byte out your page has many benefits across the board. With the feature-rich online applications these days, some pages can get bloated with necessary JavaScript libraries and associated files.  Any reduction in your production environment filesize is a help to your end users. We are currently investigating the effect of overall file size on SEO ranking and may use this technique to further optimise file sizes for (hopefully) increased effect. Thanks
    Copy & paste the code below to embed this comment.
  7. Maybe I completely misunderstood your point at the end, but are you saying that your refactoring amounted to a 5 byte saving when minified and gzipped? Is that really worth it?
    Copy & paste the code below to embed this comment.
  8. I’m all for best practices, but some of the code changes suggested in the article make the code harder for others to understand and maintain.  Not everyone is a javascript ninja like Nicholas.  After factoring in the effects of gzip, the savings don’t seem worth the extra maintenance cost.
    Copy & paste the code below to embed this comment.
  9. How much time did it take to refactor the code, in order to save a whopping 5 bytes in the gzipped file?
    Copy & paste the code below to embed this comment.
  10. A couple of people asked if all of this work is worth the 5 bytes saved after gzip. I fear my point in doing that exercise was lost slightly. The real point is that you need to be careful when applying such optimizations that you don’t take an unnecessary hit when gzipped. You can go overboard with doing optimizations and actually end up with a larger file on the wire. The example I gave was to show that you could still apply the majority of optimizations and not adversely affect the gzipped size of the response. Note, though, that the disk size (the minified column) is about 1kb smaller. This is especially important because resources are cached as uncompressed files. Mobile devices have very small caches, so minimizing disk size is incredibly important for overall web application performance.
    Copy & paste the code below to embed this comment.
  11. @nicholas
    I have to take issue with your statement:
    “Always keep in mind that anything that appears after a dot in JavaScript (object.property) cannot be minified any further.” Maybe the minifier can’t spot it, but as a general statement, it ain’t so.
    One common example is where what’s after the dot is actually an object to which a var can be assigned: Real world example this… shadow.style.overflow=‘hidden’;
    shadow.style.position=‘absolute’;
    shadow.style.top=’-5000px’;
    shadow.style.height=‘1px’; Can be this… var x=shadow.style;
    x.overflow=‘hidden’;
    x.position=‘absolute’;
    x.top=’-5000px’;
    x.height=‘1px’; Further, if what’s after the dot is a property these too can be minified if they appear more than once - using bracketed notation. Even methods can be minified this way.
    (Whether it’s worth the effort is another matter - but it can be done.) Let’s say you had two or three elements to which you are applying a particular property: objx.style.minWidth=‘200px’;
    objy.style.minWidth=‘400px’;
    objz.style.minWidth=‘250px’; *Could* become this: var a=‘minWidth’;
    objx.style[a]=‘200px’;
    objy.style[a]=‘400px’;
    objz.style[a]=‘250px’; Or, to keep in step with the previous example: var a=‘minWidth’, b=‘style’;
    objx[a]=‘200px’;
    objy[a]=‘400px’;
    objz[a]=‘250px’; With methods you can do things like this: var t = ‘toLowerCase’;
    if stringx[t]()==stringy[t]() return true; or var d = document, r=d.getElementById, obj_a=r(‘element-a’),obj_b=r(‘element-b’), obj_c=r(‘element-c’); [ In other words, getElementById() is aliased as r() ] Lastly: it can’t be stressed enough that the greatest amount of optimization can be had by simply combining scripts into a single file for a single HTTP request. I do a lot of view sourcing and I constantly see multiple script elements that can slow download - especially on the first page view before caching kicks in - that anybody, no matter what their level of knowledge, can easily avoid.
    Once combined, if minified, even better.
    Copy & paste the code below to embed this comment.