This is the mobile version of my blog. The non-mobile version can be found at http://mark.koli.ch. (hide)
Home | Newer (Next) | Older (Prev)

A Better Way to Include JavaScript and CSS in your Web-Apps (Break Proxy and Browser Caching too!)

2009-12-23T02:30:00Z

Most web-apps include a number of JavaScript and CSS files, that in most cases, need to be included/sourced on every page of the application.  Doing so can bring up a few, while trivial, often annoying problems:

Meet Gagawa, an open source object-oriented HTML generation engine written in Java and PHP.  You probably wouldn't build an entire site with Gagawa, but it's absolutely perfect for small HTML tasks, like solving this irritating dependency and caching problem.

Using Gagawa PHP, problem solved:

<?php

require_once("gagawa.php");

$js = array(
// The base jQuery library, needed by all other
// jQuery plugins and your jQuery code.
"/js/jquery-1.3.2.min.js",

// jQuery plugins; jQuery base needs to be loaded
// before you source these.
"/js/jquery.ui.min.js",
"/js/jquery.hotkeys.min.js",

// Some other, unrelated JavaScript library like
// underscore JS.
"/js/underscore.min.js",

// Your JavaScript, with dependencies on jQuery, the
// jQuery plugins and Underscore JS, should be loaded
// last.
"/js/yourjs.min.js"
);

$css = array(
"/css/othercss.min.css",
"/css/yourcss.css"
);

// Build <script ...></script> for each JavaScript
// we need, in order. Use time() to break browser
// caching.
foreach ($js as $url) {
$script = new Script("text/javascript");
echo $script->setSrc($url."?".time())->write();
}

// Build <link ...></link> for each CSS file we need,
// in order. Use time() to break browser caching.
foreach ($css as $url) {
$link = new Link();
$link->setHref($url."?".time())->setRel("stylesheet")->setType("text/css");
echo $link->write();
}

?>

This code snippet generates some solid output that fits nicely into the <head> of your HTML:

<script type="text/javascript" src="/js/jquery-1.3.2.min.js?1261531930"></script>
<script type="text/javascript" src="/js/jquery.ui.min.js?1261531930"></script>
<script type="text/javascript" src="/js/jquery.hotkeys.min.js?1261531930"></script>
<script type="text/javascript" src="/js/underscore.min.js?1261531930"></script>
<script type="text/javascript" src="/js/yourjs.js?1261531930"></script>

<link href="/css/yourcss.css?1261531930" rel="stylesheet" type="text/css"></link>

Note that each JavaScript and CSS file is loaded and added to your HTML, in order as desired, eliminating any stray dependency issues.  Also, note that I'm appending "?" and the current Epoch timestamp to the end of the JavaScript source URL, and CSS Href.  PHP's time() function works nicely here because I'll get a different timestamp on each page load.  And as far as the browser (or a web-proxy) is concerned, "/js/yourjs.min.js?1261534594" is different than "/js/yourjs.min.js?1234567890" and will be treated as such.  With this mechanism, every time you refresh the page, the browser will be forced to reload and reevaluate your scripts.  Say goodbye to browsers caching and not recognizing your changes!

You can download the latest version of Gagawa at http://code.google.com/p/gagawa/downloads/list.  Also, if you're interested, other Gagawa examples can be found on the Gagawa homepage.

If you're looking for a real, live, example of this technique in action check out Onyx.

Merry Christmas.