Create a Great Workflow for Blog Posts with Asciidoctor

Lately, I’ve been finding opportunities to use plaintext files wherever possible. Beyond the great point that the author of the linked article makes, plain text is also great in a world where LLMs can boost productivity. That’s because any plain text is easy to copy and manipulate for use with your favorite tools.

I came across the Asciidoc project, which seemed like a more powerful alternative to authoring posts in Markdown. Recently, I’ve also spent a lot of time on my current project working with remote hosts over SSH. I’ve been reaching for standard tools like Make that are available anywhere I might be remotely connected. Combining the two seemed like it might provide a great workflow for authoring blog posts. So, I set off to create this post using Asciidoctor and Make.

Setup

I created a directory for authoring blog posts containing a subdirectory for the posts themselves, a Makefile for building the posts, and a utility script for publishing them, like so:

.
├── posts
│   └── 2024-09-06.adoc
├── Makefile
└── copy-embedded.sh

The Makefile is fairly straightforward:

EMBEDDED_DIR := .embedded
FULL_DIR := .full

posts := $(wildcard **/*.adoc)
html := $(posts:.adoc=.html)
embedded := $(addprefix $(EMBEDDED_DIR)/,$(html))
full := $(addprefix $(FULL_DIR)/,$(html))

.PHONY: all clean watch

all: $(full) $(embedded)

$(full): .full/%.html: %.adoc | $(FULL_DIR)
    asciidoctor -D $(dir $@) $<

$(embedded): .embedded/%.html: %.adoc | $(EMBEDDED_DIR)
    asciidoctor -e -D $(dir $@) $<

posts/2024-09-06.adoc: ./copy-embedded.sh
    touch $@

$(FULL_DIR) $(EMBEDDED_DIR):
    mkdir -p $@

clean:
    rm -rf $(FULL_DIR)
    rm -rf $(EMBEDDED_DIR)

watch:
    while true; do make -q || make; sleep 0.5; done

The recipes to build each post use Asciidoctor to convert AsciiDoc files to HTML. Asciidoctor is a command line tool available to install via brew. I’ve included targets to compile the posts in both normal mode, which includes the entire document structure including a predefined stylesheet, and embedded mode, which only outputs the document body. The normal mode version is nice during authoring to see what the content looks like. Meanwhile, the embedded version is ready to be copied into the Atomic Spin admin site.

The watch target is taken from this stackoverflow answer, and it provides a slightly nicer experience than using watch make.

The copy-embedded script is a simple shell script that copies the embedded HTML to the clipboard. From there, it can be pasted into the admin site. It looks like this:

#!/usr/bin/env bash

cat "./.embedded/${1%*.*}.html" | pbcopy

Usage

With our directory structure set up and the Makefile in place, we can start editing our post. Because our default Make target triggers building all of our posts, we can run make watch to watch for changes and rebuild any changed posts.

All you need is to open up the built HTML file in a browser, and we can see the compiled post as we work. Once the post is ready, the body can be copied from the embedded directory by running ./copy-embedded.sh posts/2024-09-06.adoc and then pasted into the Atomic Spin admin site.

AsciiDoc Magic

So what’s so great about AsciiDoc in all this? For one, let’s talk about the Setup section.

Note that I was able to create an automatic anchor back to the setup section like this:

So what's so great about AsciiDoc in all this? For one, let's talk about the <<_setup>> section.

Within the setup section, I was able to include the Makefile itself in the post like this:

[source,makefile]
----
include::../Makefile[]
----

It includes a preprocessor directive that tells Asciidoctor to include the contents of the Makefile in the post at compile time, so any edits to the Makefile will be reflected in the post when it’s rebuilt. Asciidoctor defaults to using pre and code tags to wrap the content due to the source block. This is perfect, because that’s exactly the structure I want for a well-behaved Spin post.

The resulting HTML looks like this:

<pre class="highlight">
  <code class="language-makefile" data-lang="makefile">
    content of Makefile
  </code>
</pre>

Scratching the Surface

I’ve only scratched the surface of what Asciidoc and AsciiDoctor can do. There are lots of other great features like lists, tables, and even macros that I’ll highlight in future posts. Their Syntax Quick Reference is a great place to start getting a feel for the basics. For now, I’m thrilled with the power that comes from the preformatted code blocks and the ability to include external files, especially when authoring code-heavy posts.

Conversation

Join the conversation

Your email address will not be published. Required fields are marked *