I'm trying to set up Shake
for building a web application. At the end of my build process I would like to rename the resulting .js
and .css
files according to a content hash (for cache busting purposes).
This means of course that I do not know the final names of the files which look something like app-<hash>.min.js
.
Since the rule for building the final index.html
needs to know
about the names, I would need something like
"index.html" %> \out -> do
need [ "app-<hash>.min.js" ]
...
I've tried using a phony
action along the lines of
"index.html" %> \out -> do
need [ "revJsAndCssFiles" ]
...
phony "revJsAndCssFiles" $ do
... -- Hash and copy files to appropriate locations
This works but seems ugly since a phony
action isn't supposed to
produce a file.
What would be the best way to approach this problem?
Will the index.html
need to refer to the hashed Javascript files? If so, one approach is:
"hash-js.txt" %> \out -> do
src <- readFile' "app.min.js"
let file = "app-" ++ show (hash src) ++ ".min.js"
writeFile' file src
writeFile' out file
"index.html" %> \out ->
js <- readFile' "hash-js.txt"
writeFile' out $ "<script src='" ++ js ++ ">"
Here you have a constantly named rule (hash-js.txt
) which both produces the file you want (at an unknown location), and the name of that file (to a fixed location). That way when you need the file from index.html
you both depend on it and get the resulting filename out, which is likely to be required.
This trick works equally well if you don't need the filename in index.html
- then you just throw away the contents of the file - but it feels a bit uglier.