What are best practices for preventing stale CSS and JavaScript
Asked Answered
P

8

12

I'm researching this for a project and I'm wondering what other people are doing to prevent stale CSS and JavaScript files from being served with each new release. I don't want to append a timestamp or something similar which may prevent caching on every request.

I'm working with the Spring 2.5 MVC framework and I'm already using the google api's to serve prototype and scriptaculous. I'm also considering using Amazon S3 and the new Cloudfront offering to minimize network latency.

Philippa answered 10/12, 2008 at 15:53 Comment(0)
F
14

I add a parameter to the request with the revision number, something like:

<script type="text/javascript" src="/path/to/script.js?ver=456"></script>

The 'ver' parameter is updated automatically with each build (read from file, which the build updates). This makes sure the scripts are cached only for the current revision.

Fretwork answered 10/12, 2008 at 16:12 Comment(1)
Lots of old proxies will refuse to cache anything with a query string. it is better to use some sort of a bundler to work that id into your filename. /path/to/script-456.js is a whole lot better. Even easier to work with, /path/to/v456/script.jsHaste
I
4

Like @eran-galperin, I use a parameter in the reference to the JS file, but I include a server-generated reference to the file's "last modified" date. @stein-g-strindhaug suggests this approach. It would look something like this:

<script type="text/javascript" src="/path/to/script.js?1347486578"></script>

The server ignores the parameter for the static file and the client may cache the script until the date code changes. If (and only if) you modify the JS file on the server, the date code will change automatically.

For instance, in PHP, my script to create this code looks like this:

function cachePreventCode($filename) {
    if (!file_exists($filename))
        return "";
    $mtime = filemtime($filename);
    return $mtime;
}

So then when your PHP file includes a reference to a CSS file, it might look like this:

<link rel="stylesheet" type="text/css" href="main.css?<?= cachePreventCode("main.css") ?>" />

... which will create ...

<link rel="stylesheet" type="text/css" href="main.css?1347489244" />
Inept answered 12/9, 2012 at 22:35 Comment(0)
C
2

With regards to cached files, I have yet to run into any issues of bugs related to stale cached files by using the querystring method.

However, with regards to performance, and echoing Todd B's mention of revving by filename, please check out Steve Souders' work for more on the topic:

"Squid, a popular proxy, doesn’t cache resources with a querystring. This hurts performance when multiple users behind a proxy cache request the same file - rather than using the cached version everybody would have to send a request to the origin server."

"Proxy administrators can change the configuration to support caching resources with a querystring, when the caching headers indicate that is appropriate. But the default configuration is what web developers should expect to encounter most frequently."

http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/

Coppola answered 10/12, 2008 at 20:3 Comment(0)
C
1

Use a conditional get request with an If-Modified-Since header

Cutting answered 10/12, 2008 at 15:58 Comment(0)
S
1

This is actually a very hard issue, and something that you can spend a while engineering the correct solution for.

I would recommend publishing your files using a timestamp and/or version built into the url, so instead of:

/media/js/my.js you end up with:

/media/js/v12/my.js or something similar.

You can automate the versioning/timestamping with any tool.

This has the added benefit of NOT breaking the site as you roll out new versions, and lets you do real side-by-side testing (unlike a rewrite rule that just strips the version and sends back the newest file).

One thing to watch out for with JS or CSS is when you include dependent urls inside of them (background images, etc) you need to make sure the JS/CSS timestamp/version changes if a resource inside does (as well as rewrite them, but that is possible with a very simple regex and a resource manifest).

No matter what you do make sure not to toss a ?vblah on the end, as you are basically throwing caching out the window when you do that (which is unfortunate, as it is by far the easiest way to handle this)

Sisterinlaw answered 10/12, 2008 at 16:12 Comment(0)
K
0

If you get the "modified time" of the file as a timestamp it will be cached until the file is modified. Just use a helper function (or whatever it is called in other frameworks) to add script/css/image tags that get the timestamp from the file. On a unix like system (wich most survers are) you could simply touch the files to force the modified time to change if necessary.

Ruby on Rails uses this strategy in production mode (by default I beleave), and uses a normal timestamp in development mode (to be really sure something isn't cached).

Kowtko answered 10/12, 2008 at 18:12 Comment(0)
I
0

If you use MAVEN, you can use this, ADD on you pom.xml:

<properties>
   <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
   <timestamp>${maven.build.timestamp}</timestamp>
</properties>

With this you can acess ${timestamp} in your view. Like this sample:

<script type="text/javascript" src="/js/myScript.js?t=${timestamp}"></script>
Indefinite answered 14/8, 2015 at 18:44 Comment(0)
R
0

Based on Todd Berman's answer of incorporating a revision number into the URL (but not as a query string), a perhaps slightly more convenient approach would be to have the server transform the versioned URL into a canonical form. This could be done with symlinks, e.g.:

/media/js/v12/my.js => /media/js/my.js

or you could set up server-side URL rewrites to always transform paths of the form /media/js/v*/my.js to, say, /media/js/my.js.

Rhizopod answered 5/5, 2022 at 17:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.