Including code snippets into a blog post, such as my recent post switching a Hugo theme typically means copy-pasting snippets into your blog post text, surrounded with code fences, but makes the code unusable (it can no longer be compiled or analyzed). Similarly with the output of any given command, log file, etc.
Thus, we keep the canonical copy of the code (or the output) in an external file, and have to periodically manually copy-paste the content back into the blog post, but of course, if we forget, it’s out of date. What if we fix a bug in the code, and forget to include that fix into the blog post? Inaccuracies will confuse our future readers.
How can we automate this process?
What we need is a way to keep not just the canonical but the only copy of the code outside of the Markdown file we’re using to publish our blog post, such that it’s the one always in use by our build and run steps, and the blog post is automatically using the latest and greatest version that we have.
What we can do is use a feature of Hugo called shortcodes:
A shortcode is a simple snippet inside a content file that Hugo will render using a predefined template.
Hugo provides a rich programming environment that can do quite a lot, so thanks to a Stack Overflow answer, here’s what we can do:
Create the file
layouts/shortcodes/code.html
in your repo with the following contents:{{ $file := .Get "file" | readFile }} {{ $lang := .Get "lang" }} {{ print "```" $lang "\n" $file "```" | safeHTML }}
Now, when I create a file such as
content/blog/2019/05/some-post.md
that needs includes, I will also create a sibling directory, namelycontent/blog/2019/05/some-post/
that will house the code files,Makefile
s,Dockerfile
s, etc.
Alternatively, you can just create a directorycontent/blog/2019/05/some-post/
and put the post itself into that directory as well, namedindex.md
, since each post becomes a directory in the file tree.Then, to include the code into the post, I use a path to the file, relative to the
content/
directory, e.g.,{{% code file="/blog/2019/05/some-post/Dockerfile" lang="docker" %}}
Note: if you want to actually display shortcodes verbatim in a code region as I did above, you cannot simply write
{{% %}}
as it will give you an error; instead you need to escape the internal contents of the{{...}}
with/* ... */
. For details, see this very helpful blog post.
Now you will be able to keep your code compilable and testable, avoid errors when manually copying or sourcing in files into your blog posts, and always know you’re getting the latest version of your code snippets in your blog posts, automatically!
Since learning about this very simple approach to custom shortcodes via the
Stack Overflow answer above, I’ve updated my recent blog post switching a Hugo
theme to use these shortcodes and moved all the
Dockerfile
s code, including the diffs, into external files such that they’re
easily accessible via the docker
CLI tool.