4

I am using require.js to require JS modules in my application.

I need a way to bust client cache on new JS modules, by way of a different requested URL.

i.e., if the file hello/there.js has already been cached on the client, I can change the file name to force the browser to get the new file.

In other words, for the module hello/there, I'd like require.js to request the url hello/there___v1234___.js (the file name can look different, it's just an example), according to a version string which is accessible on the client.

What is the best way to achieve that?

Ovesh
  • 5,209
  • 11
  • 53
  • 73

4 Answers4

4

I got really frustrated with the urlArgs solution and finally gave up and implemented my own fix directly into require.js. This fix implements your ideal solution, if you are willing to modify your version of the library.

You can see the patch here:

https://github.com/jbcpollak/requirejs/commit/589ee0cdfe6f719cd761eee631ce68eee09a5a67

Once added, you can do something like this in your require config:

var require = {
    baseUrl: "/scripts/",
    cacheSuffix: ".buildNumber"
}

Use your build system or server environment to replace buildNumber with a revision id or software version.

Using require like this:

require(["myModule"], function() {
    // no-op;
});

Will cause require to request this file:

http://yourserver.com/scripts/myModule.buildNumber.js

The patch will ignore any script that specifies a protocol, and it will not affect any non-JS files.

On our server environment, we use url rewrite rules to strip out the buildNumber, and serve the correct JS file. This way we don't actually have to worry about renaming all our JS files.

This works well for my environment, but I realize some users would prefer a prefix rather than a suffix, it should be easy to modify my commit to suit your needs.

Here are some possible duplicate questions:

RequireJS and proxy caching

Prevent RequireJS from Caching Required Scripts

Community
  • 1
  • 1
JBCP
  • 13,109
  • 9
  • 73
  • 111
3

OK, I googled "requirejs cache bust" for you and found this existing SO answer, which says you can configure requireJS with an urlArgs parameter, which is only a partial solution, but it might be enough to meet your immediate needs.

That said, the cachebusting problem is full of challenges and many "solutions" don't actually solve the problem in its entirety. The only maintainable way to do this (IMHO as of now) is with a full-on asset management system like the Ruby on Rails asset pipeline or connect-assets or the equivalent for your server side framework of choice. Those can correct compute a checksum (usually MD5 or SHA1) of the content of each file and give you the file names you need to put as URLs in your HTML script tags. So, don't bother with manually changing filenames based on version numbers, just use checksums since they are easily automated and foolproof.

From what I can tell, out of the box requirejs can't do the cachebusting aspect for you. You might want to read this google groups thread. Otherwise, you may need to pair requirejs with an additional tool/script to get you good cachebuster checksums.

Community
  • 1
  • 1
Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • FYI, I don't manually rename the files. I have a rewrite in place on the server so that it just serves the file without the version string in it. Let's just say the file naming isn't the issue here, but how to get require.js to handle it correctly for me. I'll have a look at that forum post you linked to. – Ovesh Dec 12 '12 at 06:05
  • Oh, and the regular requirejs cache busting solution isn't good for me, because adding a parameter means the file is _never_ cached. I just want the browser to fetch the file when there's a new version, not on every request. – Ovesh Dec 12 '12 at 13:00
  • Did you actually read the answer I linked to? If you use a static parameter like ?v=2, that will be cached just fine. – Peter Lyons Dec 12 '12 at 15:29
  • Are you sure about that? From what I remember, parameters always disable caching. Am I wrong? – Ovesh Dec 13 '12 at 03:00
  • I don't think there's a hard and fast rule here or behavior baked into the standards, but for apache, for example, the docs state "Ordinarily, requests with query string parameters are cached separately for each unique query string". Not that presence of query string disables caching, just that ?v=24 and ?v=25 are considered 2 different resources. http://httpd.apache.org/docs/2.2/mod/mod_cache.html – Peter Lyons Dec 13 '12 at 04:49
  • I'm talking about the client side cache. Would the browser store the document in its cache if it has a query string? As far as I remember the answer is no. – Ovesh Dec 14 '12 at 00:00
  • I have never heard of a such a rule. AFAIK browsers cache according to HTTP and will check with the server for a 304 response. I believe if the URL is the same, including the query string, the browser will try to use the cached data and not re-download. It's only the crazy things you see like PHP folk append a timestamp as a query string parameter that prevent caching entirely, which is counterproductive since on the whole caching is good. – Peter Lyons Dec 14 '12 at 00:07
2

Just do it like the creator of requirejs suggests:

var load = requirejs.load;
requirejs.load = function (context, moduleId, url) {
  // modify url here
  url = url.substring(0, url.lastIndexOf('.')) + '.' + VERSION + url.substring(url.lastIndexOf('.'));
  return load(context, moduleId, url);
};

https://github.com/jrburke/requirejs/wiki/Fine-grained-URL-control

1

HTML5 Boilerplate has ant-build-script that renames your files and any reference to them for this exact reason and can do alot more. It's worth checking out if you haven't already.

GabLeRoux
  • 16,715
  • 16
  • 63
  • 81
Dennis Plucinik
  • 224
  • 3
  • 8