Developers, Please Stop Fucking With Your JavaScript Files

Posted by Matt on Thu, May 21 2009

There have been waaaaaaayyyyyy too many posts lately on "supercharging" your JavaScript (and CSS) and creating "dynamic" JavaScript. Bad. Bad. Bad Developers. For an example of what I'm talking about take a look at this article (as posted on DZone), which got 18 up diggs and is described as "Best practices for Javascript delivery..." Ugh. I could write a "Best Practices For Taking A Dump" and it would come out smelling better then that post. Let's break it down...

Client VS Server Side

I don't mean to focus on the supercharging article (which, unfortunately, also has a CSS version), there are a bunch of others too (although most don't stretch on for 7(!) pages). Like this one, which caused me to lock myself in my office for 3 hours. What happened during that time is buried so deep in my mind I'd need years of hypnotherapy to even scratch the surface.

The supercharging post opens with:

I am an unapologetic stickler for speed when it comes to Web applications.

Then he proceeds to show a method that effectively speeds up the client side of the app by slowing down the server side. The net result: probably about the same as before.

Yslow Is To Blame

Yahoo's Yslow plugin is to blame for a lot of this. It's provides nice, pretty grades and dares you to do better. It even tells you where the problems are and how to fix them. What's the easiest way to do it? Route all your JS files through your server side language! No, no, no. Wrong. You see Yslow is only measuring front-end performance. It doesn't give a shit how long something takes to generate on the server. To test that you should be using tools like ab or Siege.

Why This Matters

Your webserver, even Apache, can serve static .js and .css files a fuck ton faster then dynamic pages. This is the point where you'll counter with: "Fine. It's true I'm wasting some server resources, but everything will be cached on the client, so FU, it doesn't really matter!" Go ahead and read this article from YUI blog. Or I'll just give you the conclusion:

Keep in mind the empty cache user experience. It might be more prevalent than you think!

How Do I Know If I'm Doing It Wrong?

1) You have something in your webserver's configuration that routes .js or .css files to your server side language, like this:

RewriteRule \.js$ lib/phpsprocket.php [QSA]

2) You direct your javascript/css includes right to your programming language in your HTML, like this:

<script src="/javascript.php"></script>

Making It Fast The Right Way

Make as Few HTTP Requests as Possible

It's a good thing to merge your static files into as few as possible (notice I didn't say one - more on the later). There are a bunch of different ways to do this. Most commonly it should be part of your build routine. This way the generated file can still be a static one and will be served up fast. Heck, you could even go crazy and deploy it to a CDN.

Another way would be to have it process automatically the first time any user hits a page, as long as the results are stored as a static file for the next user. If you use a framework there might already by a library that does this for you.

GZip Everything

Something that can and should be done by your webserver.

Minify Everything

This should be part of the whatever process you have that combines your files.

Caching on the Server

Any static files that are cached on the server should be cached as plain .js or .css in a directory that is web accessible. If you need to use any type of programming to read the cached file you are doing it wrong.

Caching on the Client

As part of the build routine, when you generate the minified and combined files, include either a timestamp or a version number (preferably) as part of the file name. If you use a version number, then your HTML page (which is generated dynamically) can have access to that same number and can include it as part of the file name when it generates the tags to include your static files.

Dynamic JavaScript

I know what your thinking: "But, I need to pipe my javascript through the server side language so that I can generate custom code based on the user."
No. No you don't. Do you think any site with more then three visitors a month does this? Digg? Amazon? Twitter? You will pry my web developer badge from my cold, dead, bullet ridden body before you convince me otherwise.

The needs of the many outweigh the needs of the few...

...or one. Take a look at this simple scenario: You have a JavaScript heavy website that uses jQuery and parts of the jQuery UI on every page. Say you minify and combine those and they become one 100k file. You also have page specific JavaScript files that are around 30k each. If you were hell bent on only including one JavaScript file per page you'd end up with something like:
Page 1: file1.js (130k)
Page 2: file2.js (130K)

What if instead you left the files separate:
Page 1: jquery.js (100k) + file1.js (30k)
Page 2: file2.js (30k)

What about jquery.js on Page 2? It would already have been loaded and cached by the browser on Page 1. And if you are using the trick of including the version as part of the file name and setting a far future expires date, the browser won't even make a request for the file.

All I'm saying here is be smart. It makes more sense to logically group your files and then include the groups you need for a particular page, rather then having one giant file that gets downloaded on every page because 25% of it is different then the other pages.

Wrapping It Up

Please developers, just leave your JavaScript and CSS files as static files. It's cool if you want to mess with them a bit, but make sure the final output is still a plain static file.

Posted in Code

8 Comments

Matt said on May 22, 2009
I totally agree packing everything up into one file for all of your pages can be bad. I have found linking a lean base file and then inlining what changes on each page works pretty well. With templates it is easy to keep the CSS organized, it is easy to recombine several different CSS templates, you keep the number of requests down, and it is simple and easy to implement. Nice post, they keep getting better!
n00b said on May 26, 2009
As a newbie at this, I know how I shouldn't do it now. But I still don't know how I _should_ do it, especially "Dynamic JavaScript". How do I, as an example, build good JS with localized strings?
Matt said on May 27, 2009
Take a look at how the FCK Editor does it. They have separate static language files and just load the one that is needed. Then they can use FCKLang.Save or FCKLang.Dir or whatever throughout their code. I think this approach is pretty common.

The whole auto-language select+load is probably overkill for most, since you can just include the correct language file right in the HTML HEAD.
n00b said on May 27, 2009
Ah, yeah ok. Maybe that's easier that doing it in a good way with Cakes translation methods, __() (which I use for everything else)..?
Matt said on May 27, 2009
You should most definitely use __()...just make sure to save the output as static JS files. I would probably have a console script that runs during build and generates the various lang files, but there are other ways as well.

For example:
Setup your js like: /js/en/site.js and /js/es/site.js...Then let Cake handle those requests since the files won't exist (could use a simple route to point to some static_controller). The controller will generate the correct js based on a source js which has __() calls in it. Then cache the results, so the next time the static file is requested it can just be returned w/out Cake.
Same concept as my HTMLCache helper

I'm not saying either of these solutions is easier...just better from a performance standpoint and frankly not that hard to implement.
n00b said on May 28, 2009
I will definitely take a look at implementing it like this, my current way of mixing stuff isn't that pretty :)

Thanks Matt!
Brendon Kozlowski said on Jun 01, 2009
...speaking of your Asset plugin, I just saw someone comment that they're using it. It was left in a comment on the SixRevisions.com website on an article about speeding up your website.
"I am using cake with Matt Curry’s Asset Plugin it names files with a serialized md5 of filenames followed by a timestamp - I am getting a grade of 95 yslow", posted May 28th, 2009 by "sam".

Thought you might want to know. :)
http://sixrevisions.com/web-development/five-ways-to-speed-up-page-response-times/
Matt said on Jun 01, 2009
Cool. I'd seen that article, but didn't see the comment.