This is sort of a tradition how: I get more free time, decide to work on my blog, and instead of actually writing posts I work on the backend and don’t actually post about it until I’m done, at which point I’ve started to run out of free time.
Fortunately, this time I have a lot more free time, and the upgrades are
actually complete! Really! For real this time! (ok not really I still want
to implement syntax highlighting eventually but that’s for later ig)
The thing I’ve done: taken Hakyll’s incremental compilation abilities and extendend them to work better with my “numbered post list with links between them” format.
Why Hakyll’s Dependency Tracking is Currently Not Good Enough
With standard Hakyll, if all posts link to each other (see each other’s titles), then updating one post will update all the other posts via a link like:
post 1 --(depends on)-> post 2 --(depends on)-> ... --(depends on)-> post n
However, I’m only viewing a post’s title, not anything about its body, so a post should only be re-compiled when:
- It’s source file changes
- It depends on a post whose source file has changed
because source file changes are the only way for metadata to potentially change. Side note: depending on the metadata directly is a bit harder, with what I know now it may be possible but what I have works currently and is a bit better for numbered post lists in general.
How I Changed It
I added a new PostMetadataDependency
type to the Dependency
enum, as well as a numberedPostListMap
to the DependencyFacts
struct. Every time you make a numbered post list and use fields in its context to view titles/urls of other
pages, it makes a PostMetadataDependency
for that page through the magic of
the Compiler
monad.
If this sounds similar to how Hakyll already works, that’s because it is.
Here’s the key difference: You can have a PostMetadataDependency
on
Nothing
. Why would you want this? Say you are adding a new post to the end
of the current list of posts. This will be the new last post. The previous last post, which didn’t have a link to any later post, now needs a link to the new
last post as a later post. How else can you model “please re-compile if
something that doesn’t exist yet happens to exist in the future”?
The implementation is not elegant. I don’t know Haskell very well, and Hakyll
is quite a complicated library with many layers to dig through. In addition to
Dependencies.hs
, I also had to modify Rules.hs
(for a marker of whether
something was a numbered post list), Rules/Internal.hs
(for combining all
those markers into a map of all numbered post lists), and Runtime.hs
(for
getting that map from the result of the Rules
monad and passing that to
Dependencies.hs
). Oh and also Binary
serialization/deserialization for all
the new datastructures I created. All in all it took a lot more effort than I
expected.
Was It Worth It?
Sort of. It wasn’t a huge deal in the first place anyways, as a rebuild of all posts is very fast. But gosh darn it, if Hakyll advertises incremental compilation, then ima use it, even if I have to implement it myself.
I may also write a more thought-out blog post going into exactly how Hakyll’s
Compiler
and other systems work, now that I’ve read and re-read so much of
that code. Will have to be soon because I’m liable to forget it :P
TL;DR my blog compiles v fast because i made it do that with much haskell effort