Luminis: Forcing CSS/JavaScript Updates to Clients

Introduction

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:

HTML:
  1. <head .......>
  2.    <title>.........</title>
  3.    <script type="text/javascript" src="/js/clientsniffer.js"></script>
  4.    <script type="text/javascript" src="/js/util.js"></script>
  5.    <script type="text/javascript" src="/psu/js/combined.js"></script>
  6.    <script type="text/javascript" src="/psu/js/behavior.js"></script>
  7.    <link rel="stylesheet" type="text/css" href="/psu/style.css"/>
  8. </head>

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:

HTML:
  1. <head .......>
  2.    <title>.........</title>
  3.    <script type="text/javascript" src="/js/clientsniffer.js"></script>
  4.    <script type="text/javascript" src="/js/util.js"></script>
  5.    <script type="text/javascript" src="/psu/js/combined.js?v=1.0.0"></script>
  6.    <script type="text/javascript" src="/psu/js/behavior.js?v=1.0.5"></script>
  7.    <link rel="stylesheet" type="text/css" href="/psu/style.css?v=1.0.5"/>
  8. </head>

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

JavaScript:
  1. document.write('<script type="text/javascript" src="/js/clientsniffer.js"></script>');
  2. document.write('<script type="text/javascript" src="/js/util.js"></script>');
  3. document.write('<script type="text/javascript" src="/psu/js/combined.js?v=1.0.0"></script>');
  4. document.write('<script type="text/javascript" src="/psu/js/behavior.js?v=1.0.5"></script>');
  5. 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:

JavaScript:
  1. 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:

HTML:
  1. <head .......>
  2.    <title>.........</title>
  3.    <script type="text/javascript" src="/psu/js/pre_load.js"></script>
  4. </head>

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.

Summary

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!

Discuss This Article


One Response to “Luminis: Forcing CSS/JavaScript Updates to Clients”

  1. AvatarPlugger

    You helped me solve a problem that I’ve been thinking about for many months.

    THANKS!!

    Reply to this comment.
    1

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Comment Preview:

luminis (14) - javascript updates (8) - javascript within css (6) - javascript force download (4) - javascript write css (4) - document.write css (4) - behavior.js download (4) - load css with javascript (4) - prevent css caching (3) - load css javascript (2) - Luminis IV (2) -  (2) - javascript write css link in header (2) - forcing javascript files to load (2) - write css link with javascript (2) - css updates (2) - Luminis 4 Portal (2) - force download of css stylesheet (2) - luminis iv installation (2) - luminis wordpress (2) - browser cache javascript update (2) - css in javascript (2) - write css in javascript (2) - css script tag (2) - luminis 4 (2) - combine css js script (2) - how to write css in javascript (2) - write css with javascript (2) - force javascript to load (2) - force browser to download new css (2) - force browser to load new javascript (2) - javascript write css link (2) - load js link tag (2) - force browser to download new stylesheet (2) - javascript update css (2) - placing inline javascript in the header. (2) - force a css file from url (2) - CSS and Javascript files cached by browser? (2) - update css javascript (1) - create an inline javascript to write (1) - how to use document.write url of css (1) - force redownload of css stylesheet (1) - javascript load js nocache (1) - basic browser caching javascript (1) - load new css from link (1) - force client download new javascript (1) - what is clientsniffer (1) - force client to download new css file (1) - javascript cache js css version (1) - force redownload css (1) - javascript update browser cache (1) - JavaScript, load URL, avoid caching (1) - javascript inline Styles. combined (1) - new css update browser cache (1) - javascript force css (1) - prevent javascript from being cached (1) - html force update of css and js (1) - load css class in javascript (1) - load js no cache (1) - html force download stylesheet (1) - javascript to expire ie cache (1) - force css update (1) - load css before javascript (1) - javascript force load url (1) - load css style by ajax (1) - make sure updated css file gets loaded (1) - css inline javascript (1) - expiration date on .css .js changes the browser to download the file. (1) - browser.cache load new css (1) - html css force nocache stylesheet (1) - css javascript cache (1) - javascript change load css (1) - forcing cache link file (1) - CSS Updates download (1) - css prevent browser cache (1) - preventing cached javascript (1) - luminis 4 installation (1) - force javascript cache to expire (1) - prevent css files from caching (1) - luminis stylesheet (1) -
  • Tags