Luminis: Forcing CSS/JavaScript Updates to Clients



I gave a talk at SunGard Summit in Anaheim this spring on Plymouth State‘s portal (myPlymouth). There were a number of really great questions that came up following my presentation, one of which is the topic of this post:

“How do you force a client’s browser to always use the correct version of CSS and/or JavaScript in Luminis?”

When upgrading Plymouth State’s Luminis installation from III to IV, we had to tackle this same issue and after banging my head against the wall a number of times, I found our answer. I wanted to:

  1. Ensure that the JavaScript and CSS that is being served up to our users can be cached by their browser in order to optimize their download speeds.
  2. Control when a user’s browser has to re-download a new version of the code.
  3. Do the above within the bounds of the very restrictive caching provided by the Luminis product.

All of it was super easy to do, although I must admit I knocked my head against the wall a few times coming up with the solution to the 3rd in that list.

Step 1: Basic Browser Caching

When I sat down to tackle this problem, I knew that the inline JavaScript within nested_tables.xsl was an unforgiving issue – if I wanted to make a change to some of the inline JavaScript, those changes would not be forced upon the users until Luminis decided to let go of its cached nested_tables.xsl.

That didn’t work for me. So I ripped the inline styles out and combined a few JavaScript files into one…called combined.js.

My header within the regularLayout template in nested_tables.xslnow looked something like this:

<head .......>
   <script type="text/javascript" src="/js/clientsniffer.js"></script>
   <script type="text/javascript" src="/js/util.js"></script>
   <script type="text/javascript" src="/psu/js/combined.js"></script>
   <script type="text/javascript" src="/psu/js/behavior.js"></script>
   <link rel="stylesheet" type="text/css" href="/psu/style.css"/>

The files clientsniffer.js and util.js are SunGard delivered and I did not touch those two. As I mentioned before, I yanked out all the inline JavaScript (provided by SunGard) and dropped that into combined.js along with a number of jQuery code. Our own custom Luminis JavaScript that controls a lot of our Ajax-like functionality in myPlymouth is in behavior.js. And of course, style.css holds the CSS for our portal.

All of these files could now be cached by users’ browsers. Yay. I bounced the development portal and saw my changes in all their glory. Life was good.

Step 2: Browser Cache, Code Changes, and You

Invigorated by my recent success of effectively doing nothing, I grabbed a soda and began tackling the next objective. I had done this numerous times in my PHP applications and it was as simple as placing a version number at the end of the URLs used in the link and script tags. As such:

<head .......>
   <script type="text/javascript" src="/js/clientsniffer.js"></script>
   <script type="text/javascript" src="/js/util.js"></script>
   <script type="text/javascript" src="/psu/js/combined.js?v=1.0.0"></script>
   <script type="text/javascript" src="/psu/js/behavior.js?v=1.0.5"></script>
   <link rel="stylesheet" type="text/css" href="/psu/style.css?v=1.0.5"/>

Once again, I bounced our portal, saw the changes, and danced around the room. Step 2. Accomplished.

Step 3: Taming Versioning/Cache Expiration in Luminis

The goal of taming this versioning/cache expiration was to do so without the need for bouncing the portal so I could make changes on the fly without planning for down times. Step 2 – as I detailed above – only gets you so far. With Step 2 in place, I could easily make a change in my CSS file and edit nested_tables.xsl to one-up my version number. But, because nested_tables is cached by Luminis, that wasn’t good enough. Here’s what I came up with:

I removed the script and link tags in the header of the regularLayout template in nested_tables, created a file called load.js, and dropped the homeless script/link tags as document.writes in load.js…as so:

Start of a Solution: load.js

document.write('<script type="text/javascript" src="/js/clientsniffer.js"></script>');
document.write('<script type="text/javascript" src="/js/util.js"></script>');
document.write('<script type="text/javascript" src="/psu/js/combined.js?v=1.0.0"></script>');
document.write('<script type="text/javascript" src="/psu/js/behavior.js?v=1.0.5"></script>');
document.write('<link rel="stylesheet" type="text/css" href="/psu/style.css?v=1.0.5"/>');

But wait…

This gave me a file with all of my script/link tags and their appropriate versions. However…I couldn’t simply replace all those script/link tags with a script tag that pointed at load.js because load.js itself would be cached by users’ browsers. So this got past the Luminis caching, but not our end users. So I came up with this:

Final Solution: pre_load.js

So…I wanted to cache all my sub-files and prevent load.js from caching so that I could version my scripts easily without bouncing the portal. The solution? Yet another file! I called it pre_load.js and it looks something like this:

document.write('<script type="text/javascript" src="/psu/js/load.js?nocache=' + (new Date()).getTime() + '"></script>');

A simple document.write of a script tag with an appended variable based on time in order to prevent caching on the browser side. Yup…load.js is never cached, but it is a small price to pay.

Now my header in the regularLayout template in nested_tables.xsl looks like this:

<head .......>
   <script type="text/javascript" src="/psu/js/pre_load.js"></script>

How it works

  1. Luminis happily caches the pre_load.js script tag in the nested_tables.xsl.
  2. The JavaScript within pre_load.js writes another script tag to the document at render time. That script’s URL is a call to load.js along with a variable that changes each page load thus preventing load.js from being cached.
  3. load.js then document.writes the appropriately versioned script/link tags into the document.
  4. The individual script/link tags load the associated JavaScript/CSS files. If the browser has already cached that script/link URL (remember, we change the version numbers when we make changes to the JS or CSS), then the cached file is loaded…otherwise the new version is retrieved from the server.


The set-up is fairly basic but the results just what we were hoping! And all it took was:

  1. Placing inline JavaScript into a file (combined.js)
  2. Creating load.js to document.write script/link tags
  3. Creating pre_load.js to document.write a script tag that uses a cache-free URL call to load.js

To date, we have not had any reported issues with local or server-side caching of our JS/CSS files using this method! You just need to make sure you remember to version your URLs in load.js!

Art: Turkey Sketch

I’ve begun the design of custom headers for holiday themed portal action in Plymouth State University‘s portal. Here’s a quick turkey sketch I did with my Wacom tablet in preparation for a Thanksgiving themed header. I’m still a little undecided on what I plan to do with the header as a whole. I have a few weeks to figure that out, I suppose :)


Summit 2007 Presentation Proposal

Like Zach, its time for me to submit my Summit Presentation Proposals. My plans for submitting presentations for Student Query v2.0 and Course Query v2.0 were smashed when competing priorities at work prevented me from pushing forward with those projects. They remain in the same state as last year. Regardless, I still have one presentation proposal this year, which I’ll put below (along with my updated bio).

My Title: Self-Service Banner Administrator and Senior Web Developer

My Bio:
Matthew Batchelder is from Plymouth State University in northern New Hampshire. His titles include: Self-Service Banner Administration, Senior Web Developer, and Business Analyst. Matthew’s projects revolve heavily around Identity Management, custom Student/Prospect tools, and web-based reporting. Summit 2007 will be Matthew’s second year presenting at SungardHE’s conference – at his first, Summit 2006, he presented on “Student Reporting Through SSB.”

Building for Prospective Students
Prospective Students are a key component of every campus. They become our students, but we have to interest them first! Delivering personalized content to the Prospective Student and a solid e-mail marketing strategy in the form of a Prospective Student Portal was the direction taken by Plymouth State University. This session will walk through the steps PSU has taken to plan, develop, integrate, and implement this Prospective Student Portal.

Valve: Portal


From Xboxyde:

Valve just released this first trailer of Portal, their very experimental first person puzzle game announced with the PS3 and Xbox 360 versions of Half Life 2/Team Fortress 2. Clearly Prey gave the Valve developers some very nice ideas about how use this cool technology.

After watching the trailer…wow. This game looks awesome. You play a test subject with a portal gun where you need to locate and get to an exit while avoiding obstacles (such as walls, drops, gun fire, etc) by shooting portal entrances and exits. Anything that enters through a portal entrance will appear in the portal exit wherever that may be. Sounds simple enough, but things can get complicated. Check the trailers out for yourself:

File : First trailer (32.67 MB) (1280×720) – Streaming version
File : First trailer (11.65 MB) (640×360) – Streaming version

Sadly this game seems like it is being developed for the XBox 360 and the PS3. Lets hope it comes out for the PC…if so, I’m buying it :)

Google Widgets

In my recent post on Windows Live Gadgets I shot down Google because they hadn’t already created their own widget/gadget engine for creating hosted…well…widgets. It seems they were waiting because they could do it better. Today I found out through Slashdot that Google released their version.

Their widget API is available here. At first glance it seems that the Google widgets are a bit more robust and versatile than the Microsoft gadgets. I’ll be playing with these shortly to see what I can come up with and do a thorough compare/contrast. These are the differences I see (at first glance, mind you) between the two companies’ implementations of the same idea:

  • Google Widgets are aimed at a completely web-centric approach. They do not offer local Widgets like Microsoft Gadgets does. This is actually a win in my book.
  • Microsoft is using RSS syntax for their XML with some external javascript loaded along with it. (I’ll get more technical when I learn a bit more about the process). Google, on the other hand is using what appears to be their own proprietary markup with the inclusion of external javascript as well.
  • Microsoft’s implementation prevents the use of the id tag which makes doing some sweet dynamic stuff…well…painful. Google allows it, and goes a step further. They include a sweet little feature called __MODULE_ID__ that you can tack on to the end of your id tags so things will work fine with multiple instances of your widget on the same page. Another win for Google.

Like I said with the Windows Live and MSN Start post, I’ll be doing some heavy research into these widgets and gadgets and bring forth more details and some example code.

MSN Start & Windows Live Gadgets

MSN Start and Windows Live, which are competitors for Google/ig have jumped ahead of google and are now offering a repository for developers to create XML/javascript based ‘gadgets’!

There are two types of gadgets. A remotely hosted gadget, where a site like MasterWish would create a gadget and make the URL to the gadget’s XML file publicly available; the user then enters the URL and viola! The gadget is added! (after a confirmation) The second type of gadget is the locally hosted gadget, where you can store a gadget on your machine (Windows only). You load the gadget in the same way you do a hosted gadget…There seem to be a few catches with the local gadgets:

  • First and foremost, its not web centric…the gadget is on your machine. If you head on over to a friend’s house, that gadget won’t be available to you.
  • The local gadgets must be coded as such.
  • Windows only

The benefits with the locally hosted gadget? Well, you can do some more advanced stuff with them like messing with your local applications. For example, there are some gadgets out there that manipulate the data from iTunes…the gadgets are pretty sweet. Local gadgets are neat…but I’m not sold on them.

What really throws me for a loop is that Microsoft implemented gadgets before Google…you’d think Google would see this coming. tsk tsk tsk. All the same, I’m going to do some little experiments with gadgets and see what I can come up with.

Windows Live

I just read an article over at Slashdot about Windows Live. It seems that Microsoft has decided to attempt to clone Google/ig, while currently Microsoft’s “Windows Live” is simply a mimic, they promise to have much more.

What’s Google/ig? Its a drag and drop portal-like web app that aggregates rss feeds and some handy tools; like the weather, movie reviews, word of the day, etc. Google/ig is simplistic. Its sexy. Its Ajax heavy (which isn’t a bad thing). I’ve been using Google/ig since they released it to the public and have been thoroughly impressed. Once again Google has set the bar high enough that Microsoft has taken notice and is attempting to duplicate….and they are doing it well.

Whats sexy about Windows Live?

  • Its Free
  • Its Simplistic
  • Its using a crap ton of AJAX
  • Windows Live supposedly expects to have an online Microsoft Office Suite that will be paid for by using ads rather than money from my wallet (sounds like Writely)
  • Check out this article at for more stuff that is planned.

But in addition to all that, it seems Microsoft has adopted the Web 2.0 method of using a perpetual beta. Think about it. When was the last time that happened from Microsoft? Oh, and along with the public beta release, they also have a happy-go-lucky communication with end users. Right now I’m looking at the Windows Live site with Flock and see the following at the top of the page:

Firefox Users
Firefox support is coming soon. Please be patient :-)

Smiley face and all. Seems more personal. Seems more enticing. Makes Windows Live seem to have promise. Alright, so its just a smiley face and I may be jumping to conclusions…but I highly doubt that even Microsoft can fight the Web 2.0 and its heavy social aspects and its community driven contributions. Is Microsoft conforming? We can only hope.

Well…I can see a major drawback.

  • It uses the .NET passport. Major suck.

In closing, while Windows Live looks nifty and has some pretty cool stuff, I’m loyal to Google and will remain an avid Google/ig user until Windows Live does something that actually wows me and makes me crap my pants.