Well, I didn't find any better options, so I ended up going forward with my proposed approach above.
For the grunt task, I came across grunt-hashmap, which appeared to do everything I wanted (and more!). As I didn't want it to actually rename the files, all I had to specify in my grunt config was the following:
hashmap: {
options: {
output: 'assethash.json'
},
all: {
cwd: 'public/',
src: ['**/*']
}
}
The next piece, the Handlebars helper, looks like this (assuming params.hashes
is basically require('./assethash.json')
:
hbs.registerHelper('versionedUrl', function(file, opts) {
var hash = (params.hashes && params.hashes[file]) || '';
if (hash) file = file.replace(/(.*)\/(.*)/, '$1/' + hash + '/$2');
return (params.appRoot || '') + file;
});
This splits the path to the resource, and inserts the hash as the last path component. For example:
'js/myscript.js' --> 'js/[hashvalue]/myscript.js'
Finally, to tie it all together, the IIS rewrite rules look like this:
<rule name="Remove Static Content Version">
<match url="^(m\/js|m\/css|m\/images)/\w+/(.+)$" />
<conditions />
<serverVariables />
<action type="Rewrite" url="{R:1}/{R:2}" appendQueryString="true" />
</rule>
And that's basically it! Just wanted to post this in case others have similar questions. I am happy to hear about any improvements or suggestions you can offer, as well.