Hugo has an asset pipeline feature which can basically get an asset resource file, manipulate it (e.g. compress it, concatenate it, etc.), and then generate a final output file. I imagine most people use it for CSS and JavaScript where they minify the source, fingerprint the resource (e.g. calculate the SHA sum of the contents) and then publish the generated file. (Embedding a hash of a file into a resource’s URL works great for caching since you can add the appropriate headers and ask the browser to cache that effectively unique URL forever. When your resource changes, the resource URL will change because the generated hash in the file will be different.)
In order to make things fast, Hugo caches aggressively. So if it sees that
the contents of your file has changed, it will re-build the asset.
Unfortunately, my issue was that I had an asset (say asset S
which is an
SVG file) which included a link to another generated resource. In short, it
depended on the generation of another asset (say asset C
which is a CSS
file). Hugo would not recognize the dependency. So if I made changes to the
CSS in asset C
, Hugo would re-build asset C
but not my SVG asset S
with the new link to C
. If I made changes to asset S
, it would then
update with the latest link to asset C
.
It was somewhat annoying but understandable why this issue exists. The
solution I settled on was varying the final output path of asset S
based
on the final output path of asset C
. By varying the output path, a newly
generated asset S
would be created if C
were to change.
Here’s the sample code with an image
SVG (e.g asset S
) linking to a CSS
stylesheet and the template code which was building the SVG. The
custom.scss
is just a random stylesheet.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<?xml-stylesheet type="text/css" href="{{ .style_link }}" ?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- ... -->
</svg>
{{- $style := resources.Get "custom.scss" | resources.ToCSS | resources.Fingerprint -}}
{{- $linkSVG := resources.Get "image.svg" | resources.ExecuteAsTemplate (printf "image-%s.svg" (index (split (path.Base $style.Permalink) ".") 1)) (dict "page" . "style_link" $style.Permalink) | resources.Fingerprint -}}
{{ $linkSVG.Permalink }}
The final SVG output file would take the fingerprint from the generated CSS
file and use the CSS fingerprint in its own filename. Not exactly the prettiest
solution (it effectively becomes image-<css fingerprint>.<svg fingerprint>.svg
which is a long filename), but it’s a way to force the pipeline to re-generate
assets with hidden dependencies.