Automatic JavaScript, CSS versioning to refresh browser cache
When you update JavaScript or CSS files that are already cached in users’ browsers,
most likely many users won’t get that for some time because of the
caching at the browser or intermediate proxy(s). You need some way to
force browser and proxy(s) to download the latest files. There’s no way
to do that effectively across all browsers and proxies from the
webserver by manipulating cache headers unless you change the file name
or you change the URL of the files by introducing some unique query
string so that browsers/proxies interpret them as new files. Most web
developers use the query string approach and use a version suffix to
send the new file to the browser. For example:
Another approach is to run some build script that scans all files and updates the reference to the JavaScript and CSS files in each and every page in the website. But this approach does not work on dynamic pages where the JavaScript and CSS references are added at run-time, say using
If you have no way to know what JavaScript and CSS will get added to the page at run-time, the only option is to analyze the page output at runtime and then change the JavaScript, CSS references on the fly.
Here’s an
First, you add set the filter called
For example, the following scripts and CSS in the HTML snippet:
The
Read here to learn how this works:
Source : http://www.codeproject.com/Articles/203620/Automatic-JavaScript-CSS-versioning-to-refresh-bro
<script src="someJs.js?v=1001" ></script>
<link href="someCss.css?v=2001"></link>
In order to do this, developers have to go to all the html, aspx,
ascx, master pages, find all references to static files that are
changed, and then increase the version number. If you forget to do this
on some page, that page may break because browser uses old cached
script. So, it requires a lot of regression test effort to find out
whether changing some CSS or JS breaks something anywhere in the entire
website.Another approach is to run some build script that scans all files and updates the reference to the JavaScript and CSS files in each and every page in the website. But this approach does not work on dynamic pages where the JavaScript and CSS references are added at run-time, say using
ScriptManager
.If you have no way to know what JavaScript and CSS will get added to the page at run-time, the only option is to analyze the page output at runtime and then change the JavaScript, CSS references on the fly.
Here’s an
HttpFilter
that can do that for you. This
filter intercepts any ASPX hit and then it automatically appends the
last modification date time of JavaScript and CSS files inside the
emitted HTML. It does so without storing the whole generated HTML in
memory nor doing any string operation because that will cause high
memory and CPU consumption on webserver under high load. The code works
with character buffers and response streams directly so that it’s as
fast as possible. I have done enough load test to ensure even if you hit
an aspx page million times per hour, it won’t add more than 50ms delay
over each page response time.First, you add set the filter called
StaticContentFilter
in the Global.asax file’s Application_BeginRequest
event handler:Response.Filter = new Dropthings.Web.Util.StaticContentFilter(
Response,
relativePath =>
{
if (Context.Cache[physicalPath] == null)
{
var physicalPath = Server.MapPath(relativePath);
var version = "?v=" +
new System.IO.FileInfo(physicalPath).LastWriteTime
.ToString("yyyyMMddhhmmss");
Context.Cache.Add(physicalPath, version, null,
DateTime.Now.AddMinutes(1), TimeSpan.Zero,
CacheItemPriority.Normal, null);
Context.Cache[physicalPath] = version;
return version;
}
else
{
return Context.Cache[physicalPath] as string;
}
},
"http://images.mydomain.com/",
"http://scripts.mydomain.com/",
"http://styles.mydomain.com/",
baseUrl,
applicationPath,
folderPath);
}
The only tricky part here is the delegate that is fired whenever the
filter detects a script or CSS link and it asks you to return the
version for the file. Whatever you return gets appended right after the
original URL of the script or CSS. So, here the delegate is producing
the version as “?v=yyyyMMddhhmmss”
using the file’s last modified date time. It’s also caching the version
for the file to make sure it does not make a File I/O request on each
and every page view in order to get the file’s last modified date time.For example, the following scripts and CSS in the HTML snippet:
<script type="text/javascript" src="scripts/jquery-1.4.1.min.js" ></script>
<script type="text/javascript" src="scripts/TestScript.js" ></script>
<link href="Styles/Stylesheet.css" rel="stylesheet" type="text/css" />
It will get emitted as:<script type="text/javascript" src="scripts/jquery-1.4.1.min.js?v=20100319021342" >
</script>
<script type="text/javascript" src="scripts/TestScript.js?v=20110522074353" ></script>
<link href="Styles/Stylesheet.css?v=20110522074829" rel="stylesheet" type="text/css" />
As you see, there’s a query string generated with each of the file’s
last modified date time. Good thing is you don’t have to worry about
generating a sequential version number after changing a file. It will
take the last modified date, which will change only when a file is
changed.The
HttpFilter
I will show you here can not only append
version suffix, it can also prepend anything you want to add on image,
CSS and link URLs. You can use this feature to load images from a
different domain, or load scripts from a different domain and benefit
from the parallel loading feature of browsers and increase the page load
performance. For example, the following tags can have any URL prepended
to them:<script src="some.js" ></script>
<link href="some.css" />
<img src="some.png" />
They can be emitted as:<script src="http://javascripts.mydomain.com/some.js" ></script>
<link href="http://styles.mydomain.com/some.css" />
<img src="http://images.mydomain.com/some.png" />
Loading JavaScripts, CSS and images from different domain can
significantly improve your page load time since browsers can load only
two files from a domain at a time. If you load JavaScripts, CSS and
images from different subdomains and the page itself on www subdomain,
you can load 8 files in parallel instead of only 2 files in parallel.Read here to learn how this works:
Source : http://www.codeproject.com/Articles/203620/Automatic-JavaScript-CSS-versioning-to-refresh-bro