What I Need in a Static Site Generator
I want to create lessons and books rather than blogs, so my needs for a static site generator (SSG) are different from most people’s. Based on what I’ve built or customized over the past 15 years, here are some of the things I need:
-
Translate Markdown files into HTML and copy other resources into the right places. The translation should rely on templates, which should support loops, conditionals, parameterized inclusions, and so on (but see the next point).
-
Access to a complete programming language for templating. One of the many frustrating things about Jekyll is that its templating language only provides a limited subset of Ruby’s features: you can’t, for example, get the index at which an element appears in an array without writing a template-level loop, which is really clumsy. Tools like EJS are much, much better in this regard, and reliance on limited templating tools like Jinja is one of my few grumbles about Ark.
-
Built-in shortcodes for things like:
- glossary references,
- index entries,
- bibliographic citations,
- numbered cross-references to figures, tables, and headings (both within and between files),
- figure and table inclusions (so that they’re formatted in consistent ways)
-
Mechanisms for formatting things like bibliographies, glossaries, and indexes. For example, McCole has an extension that uses pybtex to turn a BibTeX-formatted bibliography into HTML and another that turns a Glosario-formatted YAML file into a human-readable glossary page.
-
A standard way to include fragments of source code and other files. This requirement is why I don’t use computational notebooks for my writing: I always want to include sections of code (e.g., a class header and two of its methods) rather than entire pieces of (i.e., the entire class definition), but Jupyter and its ilk don’t support that. McCole provides two mechanisms: one uses specially-formatted comments (“include everything from
# [mark]
to# [/mark]
”) and the other relies on program structure (“parse the code, walk the AST, find the functionexample
, and unparse it to text). I have other hacks to (for example) show the first and last five lines of a CSV file in a single inline code block and so on; needs like this are why extensibility (discussed below) is so important. -
Allow one subdirectory per topic to keep files manageable. For example, McCole (which is built on Ark) had a subdirectory
src/slug
for each chapter or appendix, whereslug
is a short unique identifier. And while we’re here, I always want topic order defined by configuration rather than by cross-references. This requirement may seem like nit-picking, but having to edit half a dozen files when you change the order of two chapters is a real pain. McCole defines two lists of slugs inconfig.py
calledchapters
andappendices
, and everything else refers to that. -
Titles, summaries, key points for the syllabus, and everything else in the frontmatter of each topic page. All of the information about a chapter or appendix should be in its frontmatter rather than in the configuration file or a separate data file. (I’ve done it both ways in the past; everything in one place is less error-prone.)
-
Conversely, the SSG should collect all of the frontmatter data and make it available for extensions to use in rendering. For example, each chapter of Software Design by Example starts with a list of the terms defined in that chapter. These are collected by a pre-rendering hook that scans the chapter for glossary reference shortcodes; the template has to parse every chapter itself to get that information, which adds a couple of seconds to the build.
-
Extensibility. Using McCole as an example again, it defines 27 extensions to Ark to handle things like bibliographic citations, glossary references, figure inclusions, and so on. Even if an SSG ships with all of these, every user is going to need one more.