I have noticed that some browsers (in particular, Firefox and Opera) are very zealous in using cached copies of .css and .js files, even be
Here is a pure JavaScript solution
(function(){
// Match this timestamp with the release of your code
var lastVersioning = Date.UTC(2014, 11, 20, 2, 15, 10);
var lastCacheDateTime = localStorage.getItem('lastCacheDatetime');
if(lastCacheDateTime){
if(lastVersioning > lastCacheDateTime){
var reload = true;
}
}
localStorage.setItem('lastCacheDatetime', Date.now());
if(reload){
location.reload(true);
}
})();
The above will look for the last time the user visited your site. If the last visit was before you released new code, it uses location.reload(true)
to force page refresh from server.
I usually have this as the very first script within the <head>
so it's evaluated before any other content loads. If a reload needs to occurs, it's hardly noticeable to the user.
I am using local storage to store the last visit timestamp on the browser, but you can add cookies to the mix if you're looking to support older versions of IE.
You could simply add some random number with the CSS/JS url like
example.css?randomNo=Math.random()
I recently solved this using Python. Here the code (should be easy to adopt to other languages):
def import_tag(pattern, name, **kw):
if name[0] == "/":
name = name[1:]
# Additional HTML attributes
attrs = ' '.join(['%s="%s"' % item for item in kw.items()])
try:
# Get the files modification time
mtime = os.stat(os.path.join('/documentroot', name)).st_mtime
include = "%s?%d" % (name, mtime)
# this is the same as sprintf(pattern, attrs, include) in other
# languages
return pattern % (attrs, include)
except:
# In case of error return the include without the added query
# parameter.
return pattern % (attrs, name)
def script(name, **kw):
return import_tag("""<script type="text/javascript" """ +\
""" %s src="/%s"></script>""", name, **kw)
def stylesheet(name, **kw):
return import_tag('<link rel="stylesheet" type="text/css" ' +\
"""%s href="/%s">', name, **kw)
This code basically appends the files time-stamp as a query parameter to the URL. The call of the following function
script("/main.css")
will result in
<link rel="stylesheet" type="text/css" href="/main.css?1221842734">
The advantage of course is that you do never have to change your html again, touching the CSS file will automatically trigger a cache invalidation. Works very good and the overhead is not noticeable.
For my development, I find that chrome has a great solution.
https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload
With developer tools open, simply long click the refresh button and let go once you hover over "Empty Cache and Hard Reload".
This is my best friend, and is a super light weight way to get what you want!
You can force a "session-wide caching" if you add the session-id as a spureous parameter of the js/css file:
<link rel="stylesheet" src="myStyles.css?ABCDEF12345sessionID" />
<script language="javascript" src="myCode.js?ABCDEF12345sessionID"></script>
If you want a version-wide caching you could add some code to print the file date or similar. If you're using Java you can use a custom-tag to generate the link in an elegant way.
<link rel="stylesheet" src="myStyles.css?20080922_1020" />
<script language="javascript" src="myCode.js?20080922_1120"></script>
In Laravel (PHP) we can do it in following clear and elegant way (using file modification timestamp):
<script src="{{ asset('/js/your.js?v='.filemtime('js/your.js')) }}"></script>
And similar for CSS
<link rel="stylesheet" href="{{asset('css/your.css?v='.filemtime('css/your.css'))}}">
Example html output (filemtime
return time as as a Unix timestamp)
<link rel="stylesheet" href="assets/css/your.css?v=1577772366">