Sunday, November 30, 2008

JavaScript packaging

With the current generation of browsers page load time is highly depended on the number of JS files loaded. Thus it makes sense to minimize the number of http-requests by combining multiple JS files in combined packages. This makes even more sense because the effectiveness of gzip-compression increases on larger JS files as opposed to the same source distributed over multiple files.

Most advanced JS projects will have some kind of mechanism within there build process to statically determine which JS files are needed for a particular page or application and assemble these together (JavaScript minification with a tool like the yui-compressor would also we applied at this point).

Here are some common simple strategies to make those JS packages:
  1. Traverse the JS directory recursively and put all files into the package
  2. Mantain a list of JS files per page/site/app and use that to assemple the JS packages
  3. Include support in the templating system to arrange for the generation of an appropriate JS package
We are currently using a modified version of strategy 2 at work. Every page loads a "meta" JS file that mostly defines an array of needed JS files. During development this file actually generates script tags via document.write to load the required files. This makes sense because during debugging you want to have errors and break points per file. Once we deploy the application for testing, a program analyzes those "meta" JS files to compile packages that are then loaded instead of the meta files.

In a recent post to the Joose mailing list, we talked about different strategies to find the ideal packages to minimize load time. My current thinking is that it is very hard to do much better than to load everything (for the whole app / sub-site) at once.

Here are some examples for strategies to determine what to put inside a JS package:

Page A needs JS file 1,2,3,4,5
Page B needs JS file 2,3,4,5,6

In order to minimize http requests, the strategies would be to

Strategy X:
1. Visit page A , load a package containing all needed JS files
2. Visit page B, once again load a package containing all needed JS files
  • plus: Simple
  • minus: Loading too much data
Strategy Y
1. Visit page A, load a package containing all needed JS files
2. Visit page B, somehow determine that we were already in Page A and use that package plus and extra request for file 6
  • plus: Minimal data
  • minus: Very complex, needs support on the server for dynamically assembling JS packages.
Strategy Z:
1. Visit page A Load a package containing all needed JS files for the entire App
  • plus: Simple
  • plus: Maximum result from zip-compression
  • minus: User loads code which he might not need eventually
My current thinking is, that if (and only if) the package resulting from strategy Z is not "too large" it is the best strategy most of the time.

If it is possible to easily determine disjunct packages of JS files, it makes of course sense to load these separately. In this case, it is, however, highly likely that we are talking about separate applications anyway.
Post a Comment