ddraper

Checksum Dependencies In Surf

Blog Post created by ddraper on Mar 6, 2012
Please note: The following features are at the time of writing only available in the Alfresco Community source code and have not as yet been included in any release.

Introduction



One of the problems that has affected upgrades of Alfresco in the past is that the end-users’ browsers may end up using cached copies of JavaScript and  CSS files that have been updated during the upgrade.  Spring Surf now has introduced a new service called the “DependencyHandler” which has been created to solve this specific problem. It does this by appending a unique checksum to the end of each requested JavaScript and CSS dependency where the checksum is generated from the contents of the file and so will change whenever the file content is changed. The checksum associated with the file is cached for the lifecycle of the web server meaning that it does not need to be generated for each request and Surf performance has actually been enhanced by this mechanism because Surf also caches the location from which the dependency is retrieved (Surf can retrieve dependencies from a number of different locations, e.g. JAR files, class path, file system, remote location, etc.).

Configuration and Usage



By default the capability is disabled in Surf but will be enabled in future releases of Alfresco Share. To enable is you simply need to set the following line within the Surf configuration (this can be found in the “webapps/share/WEB-INF/surf.xml”):

<web-framework>

   …

   <use-checksum-dependencies>true</use-checksum-dependencies>

   …

</web-framework>


In order to make use of the dependency handler you will need to use  the <@script>, <@link> and <@checksumResource> FreeMarker directives in your  TemplateInstance and WebScript files, e.g.

<@script src='${url.context}/res/yui/yahoo/yahoo.js'></@script>

<@link rel='stylesheet' type='text/css' href='${url.context}/res/css/base.css' />

<@checksumResource src='${url.context}/res/css/ipad.css'/>


(Those examples are taken from the resources.get.html.ftl file  where the ${url.context} is a FreeMarker variable set to the application  context, e.g. “share”)



  • <@script> generates JavaScript script import declarations.


  • <@link> rolls up multiple CSS requests into a style declaration using a separate '@import' statement for each usage of <@link>.


  • <@checksumResource> generates just the URL (i.e. without being specific to CSS or JavaScript and can therefore be used with images or even WebScript requests. One additional feature of the <@checksumResource> directive is that you can specify the attribute 'parameter' which makes the checksum appear as the value of a request parameter of the supplied name (rather than as part of the file name itself).


Debug and Production Suffices



The DependencyHandler is capable of dealing with production (minified) and debug versions of files and actually handles these better than before. The Spring application context configuration for the bean allows you to specify the different file suffices that can be used for both production and debug versions and the DependencyHandler will work through the options until it finds a file. This means that Surf will always be able to fall back to the debug version of the code if a minified version does not exist. By default the debug suffices are:



  • “” (i.e. no suffix)


  • “_src”


  • “-debug”


And the production suffices are:



  • “-min”


  • “-minified”


  • “” (i.e. no suffix)


You can change these suffices by overriding the definition for the “dependency.handler” bean in the Spring application context in case you want to add, remove or re-order the default entries.

Example



The following screenshot shows the Chrome Developer Tools window displaying the JavaScript resources loaded for a page in Alfresco Share - note that each request is appended with a checksum value (apart from 'tiny_mce.js' which handles its dynamic dependencies in its own way).





Current Limitations



The current limitation of this solution is that it only works with static requests from the page and not dynamic requests made from a script – although many JavaScript libraries provide their own solution to this problem (e.g. TinyMCE) however it is something to be aware of.

Outcomes