Recently in my current work i'd to deal with a requirement where we had a couple of common JS libraries and some common CSS files along with some custom JS and CSS per user too. If you read the above two links, you must be thinking about JS and CSS compression for each of these files. There is an issue though, you will be hitting your server multiple times for each of these files. Since its common for a sufficiently large project to have multiple JS and CSS files, you've to make a choice between combining all the code into very few files vs keeping individual application logic separate. Well i decided to keep them separate :) This may sound absurd, but here is the learning from Y! days that helped me, i decided to not only load them in one go, but as well compress them. Thanks to YUICompressor (it was easy to adapt since its java based). As far as compression performance is concerned, once you compress it, you can always keep it cached for future transmissions. Some data on the performance:
JS - fairly complex (extjs based OO JS) - 1.4 MB - 532 msec - compression achieved 56%
CSS - fairly complex - 1.1 MB - 328 msec - compression achieved 52%
Now depending on the complexity of these source files, the compression might differ, but i'm confident it should not vary way too much from what i've mentioned above.
In our case, we had strict performance requirements to serve most of the requests in sub msecs, so we decided to go the caching way, otherwise i don't think on the fly compression of JS/CSS using YUICompressor is any bad (looking at the numbers above). Below is the code for the portion that does compression (again, its not mine, credit goes to the creators of YUICompressor, i just stripped this piece for my purpose)
JavaScriptCompressor compressor = new JavaScriptCompressor( new FileReader("original.js"), new ErrorHandler()); StringWriter out = new StringWriter("new.js"); int linebreakpos = 80; boolean munge = true, verbose = false, preserveAllSemiColons = false, disableOptimizations = false; compressor.compress(out, linebreakpos, munge, verbose, preserveAllSemiColons, disableOptimizations);
class ErrorHandler implements ErrorReporter { public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) { if (line < 0) { System.err.println("\n[WARNING] " + message); } else { System.err.println("\n[WARNING] " + line + ':' + lineOffset + ':' + message); } } public void error(String message, String sourceName, int line, String lineSource, int lineOffset) { if (line < 0) { System.err.println("\n[ERROR] " + message); } else { System.err.println("\n[ERROR] " + line + ':' + lineOffset + ':' + message); } } public EvaluatorException runtimeError(String message, String sourceName, int line, String lineSource, int lineOffset) { error(message, sourceName, line, lineSource, lineOffset); return new EvaluatorException(message); } }
CssCompressor compressor = new CssCompressor(new FileReader("original.css")); StringWriter out = new StringWriter("new.css"); int linebreakpos = 80; compressor.compress(out, linebreakpos);One could very well pass a "null" instead of the ErrorHandler instance but make sure that verbose is set to false, else you will get a NPE. So this is just the compression part, what about reducing the number of requests?? Well so i created a servlet that basically takes all the required parameters for loading these static resources and serves them from cache or classpath (well some intelligence required here to avoid serving unwanted stuff but thats pretty straight forward. If you want to know what i did for this, post in comments and i will see if i should post that as well). And just FYI, Y! does similar thing for distributing such files through CDN. Just go to any of the pages on yahoo.com and you would see script urls of the kind
- http://yui.yahooapis.com/combo?2.8.0r4/build/animation/animation-min.js&2.8.0r4/build/connection/connection-min.js&2.8.0r4/build/container/container-min.js
No comments:
Post a Comment