Handleblog Sneak Peak: Excerpt Logic and Markdown Parsing Fail

Aug 18, 2023 handleblog

This post is a sneak peak behind the scenes of the blog platform hosting the post your are now reading - Handleblog.

I have talked about the Law of Least Astonishment many times in this blog and probably even more often IRL. A blog behavior that meets this law is to automatically create excerpts for blog posts when listing posts so I set out to write a function to render an excerpt based on the following logic:

  • Excerpt must be text only
  • Excerpt length must be less than or equal to a specified value (500 characters by default)
  • Excerpt should break at the end of a sentence (at least following an instance of .)
  • Excerpt should be 80% of max length. If less than that, try breaking on a space instead of a period
  • If we still can't get to 80%, just break regardless of the character

Since the posts are stored as markdown, converting to text seemed pretty simple. At first, I was going to try to find a utility to strip the markdown from the post but then I realized I was already using a custom renderer to handle custom roots for images as I described above. I just needed to write a custom renderer to return an unformatted version each of the various markdown elements. Easy peasy lemon squeezy! Until it wasn't.

Everything worked great at first. I was able to convert my markdown to plain text and then trim it down to the desired length. The list of posts rendered just how I wanted, but then when I rendered a post, it was rendered without any formatting like it was an excerpt. So I found this section of the documentation for marked:

All options will overwrite those previously set, except for the following options which will be merged with the existing framework and can be used to change or extend the functionality of Marked: renderer, tokenizer, walkTokens, and extensions.

The renderer and tokenizer options are objects with functions that will be merged into the built-in renderer and tokenizer respectively.

Aha! So I just need to make sure I merge my custom renderers with a default renderer and then everything should work perfectly, right? Wrong.

Now the first time I render the post after rendering the list of posts, it renders as an excerpt but then will render correctly when I refresh. Strange. I'm still looking for the smoking gun on this issue. I believe what is going on, but have yet to confirm, is the renderers are being called in sequence so the excerpt renderer is being called first which is stripping all markdown so the second renderer has nothing to do. The fix ended up looking like this:

      marked.defaults.renderer = this.bodyRenderer;