Automating JS and CSS Versioning

For a very long time we have been telling users, developers, testers and frankly everyone that uses our web application, that they should clear their cache in order to receive the latest version of a JavaScript or Cascading Style Sheet.

This is a very poor solution to a common problem, so what are our options?

  • Change the name of the resource file when updated.
  • Use Output Caching rules in IIS 7.
  • Append a version number to the query string when a file is modified.

Altering the name of a file when it has been changed or updated would be the best solution, but is also the most costly and error prone and for these reasons this option was discarded.

Within IIS 7 output caching rules can be set up to return the latest version of a file once it has been modified, or after a set period of time.  This solution appeared the simplest but to be honest was something we knew very little about, and was the reason we didn’t go down this route.

We had already begun appending a version query string manually in some parts of the application and this was the main contributor to selecting this option. However having manually entered a version number myself I know how cumbersome and error prone this is.

The decision was made that we wanted to use the query string to indicate the version number forcing the client to get the latest version of the resource, but we wanted this approach to be automated.

In the system we had a mix of the following script tags:

<script src=”../shared/js/MyJavascript.js" type="text/javascript" language="javascript"></script>

and

<script src=”../shared/js/MyJavascript.js?v=1.0" type="text/javascript" language="javascript"></script>

The second example is what we intend to automate. In order to do this we need a number that increases automatically that can be appended to the query string. The assembly version is suitable as it is managed as part of the build process and can be set to increase automatically. It is also updated as part of our deployment process meaning that the version number will match the version number of the software, this is not required but is kinda neat.

This solution will retrieve not only the modified files, but a new copy of all JS and CSS files after deployment. This will only happen once after deployment so we were happy with this implementation.

Assembly Version

The assembly version can be set within the AssemblyInfo.cs file of any visual studio project, and is located at the bottom of the file.

[assembly: AssemblyVersion("1.0.*")]

The build number can be replaced with a * which will then be updated at build time. The build number is the number of days since January 1, 2000 local time, and the revision is the number of seconds since midnight local time, divided by 2 (as detailed here).

This unique and increasing number can then be appended to the resource URL.

Append the Version Number

A method can then be created to read the version number and append it to the query string.

/// <summary>
/// Gets or sets the assembly version.
/// </summary>
private static string AssemblyVersion { get; set; }

/// <summary>
/// Appends a version number to thje query string of a resource Url.
/// </summary>
/// <param name="resourceUrl">The resource Url.</param>
/// <returns>The url with the query string of version added.</returns>
public static string AppendVersion(string resourceUrl)
{
   if (string.IsNullOrEmpty(AssemblyVersion))
   {
      AssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
   }
   return string.Concat(resourceUrl, "?v=", AssemblyVersion);
}

This method can now be called when registering your CSS or JS file:

<script language="javascript" src="<%= VresionManager.AppendVersion("../shared/js/MyJavascript.js")%>" type="text/javascript"></script>

Conclusion

This approach offers a simple programmatic solution to version control of JS and CSS files, all be it a slightly overcooked approach. Using output caching rules within IIS 7 is worth exploring if you want a non programmatic approach to this problem.

Advertisement

3 comments

  1. I received the following comment on http://www.reddit.com/ and wanted to share it with my readers, as it raised a very valid point:

    Is it just me or did anyone else lose all confidence in the author at “This solution appeared the simplest but to be honest was something we knew very little about, and was the reason we didn’t go down this route.”

    If a solution appears to be the best one, you look into it. My guess is that it wouldn’t have taken them much longer to learn how to do this than it took to go through their code and wrap all their script urls with this new function. Sure, it’s not hard to remember to use this function when embedding script in the future, but every hack like this increases the cost to train new employees, and also increases the chance they will forget to do this and waste time figuring out what went wrong.

    That said, this is a pretty elegant solution if your Web server’s caching rules are not configurable enough to meet your use case. This is a dirty hack if you were just too lazy to properly configure your damn Web server.

    I also wanted to share my reply as I think it contains detail I should have included in the post:

    Thanks for taking the time to read my post. I appreciate your comment about ignoring what I stated is the simplest approach. I think I should have added more detail as to why this option was not suitable.

    I was looking for a solution that was programmatic because I wanted to take the responsibility away from deployment and have it fixed in the solution. I did however still spend some time researching the Output Caching rules within IIS 7 and wanted to mention it for those that were happy to put the responsibility on deployment.

  2. […] Automating JS and CSS Versioning […]

  3. Great article thanks. I opted to use the date stamp of the actual JS/CSS/Image file in each case. Like you, I didn’t want to leave things to chance so wanted to fix in the application rather than rely on servers being set “correctly”.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: