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
Simply add this code, where you want to do hard reload (force browser to reload cached CSS/JS files ) Do this inside the .load so it does not refreshes like a loop
$( window ).load(function() {
location.reload(true);
});
Interesting post. Having read all the answers here combined with the fact that I have never had any problems with "bogus" query strings (which I am unsure why everyone is so reluctant to use this) I guess the solution (which removes the need for apache rewrite rules as in the accepted answer) is to compute a short HASH of the CSS file contents (instead of the file datetime) as a bogus querystring.
This would result in the following:
<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />
Of course the datetime solutions also get the job done in the case of editing a CSS file but I think it is about the css file content and not about the file datetime, so why get these mixed up?
Just use server side code to add the date of the file... that way it WILL be cached and only reloaded when the file changes
In ASP.NET
<link rel="stylesheet" href="~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />
<script type="text/javascript" src="~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>
This can be simplified to:
<script src="<%= Page.ResolveClientUrlUnique("~/js/custom.js") %>" type="text/javascript"></script>
By adding an extension method to your project to extend Page:
public static class Extension_Methods
{
public static string ResolveClientUrlUnique(this System.Web.UI.Page oPg, string sRelPath)
{
string sFilePath = oPg.Server.MapPath(sRelPath);
string sLastDate = System.IO.File.GetLastWriteTime(sFilePath).ToString();
string sDateHashed = System.Text.RegularExpressions.Regex.Replace(sLastDate, "[^0-9]", "");
return oPg.ResolveClientUrl(sRelPath) + "?d=" + sDateHashed;
}
}
I've heard this called "auto versioning". The most common method is to include the static file's mtime somewhere in the URL, and strip it out using rewrite handlers or URL confs:
See also:
Thanks at Kip for his perfect solution!
I extended it to use it as an Zend_view_Helper. Because my client run his page on a virtual host I also extended it for that.
Hope it helps someone else too.
/**
* Extend filepath with timestamp to force browser to
* automatically refresh them if they are updated
*
* This is based on Kip's version, but now
* also works on virtual hosts
* @link http://stackoverflow.com/questions/118884/what-is-an-elegant-way-to-force-browsers-to-reload-cached-css-js-files
*
* Usage:
* - extend your .htaccess file with
* # Route for My_View_Helper_AutoRefreshRewriter
* # which extends files with there timestamp so if these
* # are updated a automatic refresh should occur
* # RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
* - then use it in your view script like
* $this->headLink()->appendStylesheet( $this->autoRefreshRewriter($this->cssPath . 'default.css'));
*
*/
class My_View_Helper_AutoRefreshRewriter extends Zend_View_Helper_Abstract {
public function autoRefreshRewriter($filePath) {
if (strpos($filePath, '/') !== 0) {
// path has no leading '/'
return $filePath;
} elseif (file_exists($_SERVER['DOCUMENT_ROOT'] . $filePath)) {
// file exists under normal path
// so build path based on this
$mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $filePath);
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
} else {
// fetch directory of index.php file (file from all others are included)
// and get only the directory
$indexFilePath = dirname(current(get_included_files()));
// check if file exist relativ to index file
if (file_exists($indexFilePath . $filePath)) {
// get timestamp based on this relativ path
$mtime = filemtime($indexFilePath . $filePath);
// write generated timestamp to path
// but use old path not the relativ one
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
} else {
return $filePath;
}
}
}
}
Cheers and thanks.
Have not found the client sided DOM approach creating the script node (or css) element dynamically:
<script>
var node = document.createElement("script");
node.type = "text/javascript";
node.src = 'test.js?'+Math.floor(Math.random()*999999999);
document.getElementsByTagName("head")[0].appendChild(node);
</script>