Tag: javascript

Recently, I tweeted:

 

which prompted:

 

Unfortunately, the code I was referring to was client code, but how about a blog post?

The Widget Problem

For whatever reason, I have been writing lots of Javascript widgets and bookmarklets.  This type of 3rd-party code is usually copied and pasted into a website or initiated via a boorkmark (both work in similar fashion). The tricky party about widgets is that the code must be lean and fast, and must be robust to hostile environments.  By hostile environments, I mean that you can’t make any assumptions about a particular website these days.  If you’ve ever tried to scrape arbitrary webpages, you know what I’m talking about.

The problem with jQuery is that sometimes it is neither lean nor fast, and you can’t assume that the website hosting your widget has jQuery already, or has a particular version of jQuery.  But we need jQuery.  We need its selectors, and Ajax helpers, and CSS helpers.  The solution is to load our own jQuery.

I Got Mine (jQuery)

Start with the typical function expression module that isolates your code from any other Javascript.

(function(document, undefined) {
 
  // ... your isolated code
 
})(document);

Load jQuery asynchronously, and prepare a callback that runs when jQuery is loaded.

(function(document, undefined) {
 
  // Load our own jQuery
  s = document.createElement('script');
  s.src='//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js';
  s.onload = function() {
    // ... 
  });
 
  d.getElementsByTagName('head')[0].appendChild(s);
 
})(document);

When jQuery loads, it will assign itself to the $ variable, overwriting whatever was using it beforehand, such as the host site’s copy of jQuery.  Fortunately, jQuery keeps a copy of the original value, and running jQuery.noConflict() restores the original value of $ and returns the latest value.  Run $.noConflict() to get our own, local copy of jQuery in the $ variable.

(function(document, undefined) {
 
  // Load our own jQuery
  s = document.createElement('script');
  s.src='//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js';
  s.onload = function() {
    var $ = jQuery.noConflict();
    // ... $ now safe to use
  });
 
  d.getElementsByTagName('head')[0].appendChild(s);
 
})(document);

Can We Do Better?

This works well. However, if the thought of a whole network request (even if cached) just to run your widget bothers you, there’s a surprisingly simple alternative: inline jQuery.  That is, copy and paste the entire jQuery library into your widget code.  This may seem unusual, but despite it’s size, it’s still cheaper than a network request.

(function(document, undefined) {
 
  // Load our own jQuery
  /*! jQuery v@1.8.1 jquery.com | jquery.org/license */
  (function(a,b){function G(a){var b=F[a]={};return ...
 
  var $ = jQuery.noConflict();
  // ... $ now safe to use
 
})(document);

Can We (Still) Do Better?

If inlining all 91k (as of 1.8.2) of jQuery also bothers you: consider Zepto (23k for 1.0RC1). Zepto is billed as a minimalist JavaScript library for modern browsers with a largely jQuery-compatible API.”

(function(document, undefined) {
 
  // Load our own Zepto
  /* Zepto v1.0rc1 - polyfill zepto event detect fx ajax form touch - zeptojs.com/license */
  (function(a){String.prototype.trim===a&&(String.prototype ...
 
  var $ = window.Zepto;
  // ... $ now safe to use
 
})(document);

Zepto, unlike jQuery, will not assign itself to $ if it is already defined, so no issue there.

Now, don’t make the mistake I did in thinking Zepto is a drop-in replacement as a “lightweight” jQuery because it certainly is not, especially in CSS manipulations.  Support for CSS effects in IE is sketchy, and its Ajax helpers are a bit different.  However, Zepto gives you all the selectors and DOM manipulators you’re used to, has all the Ajax helpers you need, and offers useful utilities such as $.proxy().

So if you need visual effects in your widget, Zepto will probably not do. But if all you need is the ability to add/remove/select elements, then Zepto works great as a jQuery replacement.

Serving Javascript and CSS

Editor’s note: This post formed the basis of the Front-End Optimization talk I’ve given in the past.

You’ve programmed websites for years, know the ins & outs of PHP, MySQL, why are Javascript and CSS files such a big deal? You put them in a directory, and link to them from your pages. Done. Right?

Not if you want maximum performance.

According to the Yahoo Exception Performance team:

…Only 10% of the time is spent here for the browser to request the HTML page, and for apache to stitch together the HTML and return the response back to the browser. The other 90% of the time is spent fetching other components in the page including images, scripts and stylesheets.

So static content is very important. The same Yahoo people provide us with a comprehensive list of Best (Front-end) Practices for Speeding Up Your Website.  IMO, some of the rules are more important than others, and some are more easily achieved.  Leaving aside hardware solutions (static server, CDN, etc.) for now, let’s look at six of the rules:

  1. Rule 1: Make Fewer HTTP Requests, or combine files. The less downloads the better. Simple file concatenation would do. Our goal is at most one Javascript and one CSS file per page.
  2. Rule 3: Add an Expires Header, or every static file must accompany a time-stamp so we can take advantage of the HTTP Expires: header. A time-stamp in the GET parameters might work, but some say that some CDN’s and browser/version/platform combinations will not request a new file if the query string changes. A better solution would be to put the time-stamp in the filename somewhere.
  3. Rule 4: Gzip Components. This is easily achieved by enabling mod_deflate in Apache.
  4. Rule 9: Reduce DNS Lookups. Okay, the real value in this rule is introducing parallel downloads by using at least two but no more than four host names. This is better explained here.
  5. Rule 10: Minify JavaScript, or at the least strip out all whitespace and comments. There are more sophisticated compressors out there that replace your actual variables with shorter symbols, but the chances of introducing bugs is higher.
  6. Rule 12: Remove Duplicate Scripts, which as they say is more common than you think.

Rule 3 is a matter of configuring Apache. How to achieve the other five?

As I see it, there are three broad ways to achieve them.

  1. Handle every request in real-time.  This means using a PHP file to serve the files (e.g. <link rel="stylesheet" type="text/css" href="custom_handler.php?file1.css,file2.css" /> or something like that).  It can also mean using mod_rewrite to direct incoming requests for CSS and Javascript to go to a PHP script. Either way, there is processing on every page load. Caching the end-product helps. Still, there must be a better way.
  2. Use a template or view plugin.  If you are using a templating system to dynamically generate your HTML, you can use some sort of plugin or function to read in a list of static files, check their last-modified times, and if changed build a combined, minified, time-stamped output file to serve up.  This is better than method #1 because by the time the page is built, there is a static file that is simply served to the browser.  Still, there must be a better way.
  3. The best way is to do it offline.  This means a job that checks static files to see if they’ve been modified.  If so, it processes the files and builds the output file that is directly served to the browser.  This job could be run in cron, or run manually by developers, but the best way is to make it a part of the build server.

Don’t have a build server?  That’s a whole other topic.