Prevent Requirejs from Caching Required Scripts

Prevent RequireJS from Caching Required Scripts

RequireJS can be configured to append a value to each of the script urls for cache busting.

From the RequireJS documentation (http://requirejs.org/docs/api.html#config):

urlArgs: Extra query string arguments appended to URLs that RequireJS
uses to fetch resources. Most useful to cache bust when the browser or
server is not configured correctly.

Example, appending "v2" to all scripts:

require.config({
urlArgs: "bust=v2"
});

For development purposes, you can force RequireJS to bypass the cache by appending a timestamp:

require.config({
urlArgs: "bust=" + (new Date()).getTime()
});

Expire cache on require.js data-main

How are you defining your require.config? I think for it to take effect before you import require.js, you need to code it like this:

<script type="text/javascript">
var require = {
baseUrl: "/scripts/",
waitSeconds: 15,
urlArgs : "bust="+new Date().getTime()
};
</script>
<script data-main="app/main" src="/scripts/require.js"></script>

Specifically, a an object named 'require' must be constructed before you import require.js.

UPDATE

As Jesse points out in the comments below, there are a few enhancements you should apply to your require{} object for production use. The above example is cribbed from the RequireJS documentation and modified as little as possible to answer this question.

Here are a few things to consider for production use:

  • Instead of using the current date-time as your cache-busting variable, you should use a build number from your development environment. This allows your clients to cache the Javascript between releases but will cause them to refresh their cache whenever you do a software update.
  • Jesse also uses the require{}'s ability to specify dependencies instead of using the data-main attribute of the script. I don't know if that is strictly better, but I think it is cleaner looking.
  • Adjust the waitSeconds based on your needs. I used the example value from the RequireJS documentation, but you should adjust the value or omit it, based on your needs.

So if you apply these techniques, your code might look like:

<script type="text/javascript">
var require = {
baseUrl: "/scripts/",
waitSeconds: 15,
urlArgs : "bust="+{{buildNumber}},
deps : ['app/main']
};
</script>
<script src="/scripts/require.js?bust={{buildNumber}}"></script>

Note, in this case {{buildNumber}} is a value supplied by the server.

UPDATE 2

The urlArgs cache bust solution has problems. Unfortunately you cannot control all proxy servers that might be between you and your user's web browser. Some of these proxy servers can be unfortunately configured to ignore URL parameters when caching files. If this happens, the wrong version of your JS file will be delivered to your user.

I would recommend using a buildNumber in your Javascript filename request, like buildNumber.myModule.js (prefix) or myModule.buildNumber.js (postfix). You can use the prefix style by modifying the baseUrl:

baseUrl: "/scripts/buildNumber",

Note the lack of a '/' at the end of the baseUrl.

You will need to use a modified version of require.js to use the postfix solution. You can read more about this here: https://stackoverflow.com/a/21619359/1017787

Obviously in either case you will want to use some solution to replace buildNumber with some type of version number that changes with each release.

Prevent require.js from caching text files?

According to the requirejs doocumentation you can "undef" a module:
http://requirejs.org/docs/api.html#undef

This won't free memory for pieces of your code that have already required the module, but for those you could unset the local version via my_module = undefined.

Prevent browser cache issue on Javascript files with RequireJS in SeedStack

The module configuration values, like apiUrl in your example, are not touched by RequireJS unless you call require.toUrl() on them explicitly. I think this is what is happening in your case. To avoid this problem, you should always do the concatenation first and only then call require.toUrl() on the full resulting URL.

So, instead of doing:

var fullUrl = require.toUrl(config.apiUrl) + '/my/resource';

Do this:

var fullUrl = require.toUrl(config.apiUrl + '/my/resource');

By the way, instead of setting the version directly in the RequireJS configuration, you can simply add the version of your application to the data-w20-app-version attribute on the <html> element of the master page:

<html data-w20-app data-w20-app-version="2.0.0">

This will provide the same behavior but will work correctly in the case of Angular templates in $templateCache. If your master page is automatically generated by the backend, this is done automatically. Check this page for the details.



Related Topics



Leave a reply



Submit