How this site works
This site uses a custom static rendering engine built in Python to parse and generate pages. At its core, it takes in raw markup, parses a block of frontmatter into a combined site and page context, and then outputs templated HTML files for each page.
This approach isn't entirely dissimilar to Jekyll, currently in use on my blog, but offers a few personal advantages:
- Simplicity: Basic pages like this one can be generated from an HTML file limited to just the content. When needed, more complex pages that require pre-processing can go through a Python layer. As a big believer in progressive enhancement, Javascript is strictly optional.
- More extensible: Jekyll is built almost entirely on parsing Markdown, engineered to support blogs. Much like Wordpress or Drupal, you can bend it to your will to do a lot more, but it's hardly a recommended approach. With the Python layer, we already have the scaffolding that makes it possible to introduce addditional entry points to more complex pages. We can also easily inject markup in different formats (template strings, template files, injected strings).
- Python: Gemfiles are a moderate packaging headache that I'm willing to overcome, but Python gives us access to a huge library of modern packages that aren't maintained in Ruby, especially those integrated with third-parties. Python has a robust standard library, and the packages don't bloat as badly as Node does.
- Custom built, but collapsable: Everything was built from the ground up, pared down to what brings value. If the headaches ever become too much, it's easy enough to abort the project entirely with flattened HTML.
Generating pages
The site directory is walked through looking for all index.* files. Based on the file's extension, like .py or .html, the file is then sent to an accompanying rendering hook. For .html:
# TODO
For .py:
# TODO
The site's generate layer by default walks the entire site directory and creates every page, but also supports targeted builds. With a local server serving the pages and listening for create or modify events on files, it's possible to build specific paths or targets, much like Jekyll in a development environment:
class RebuildHandler(FileSystemEventHandler):
def __init__(self, watch_dir, output_dir):
self.watch_dir = os.path.abspath(watch_dir)
self.output_dir = os.path.abspath(output_dir)
def on_modified(self, event):
abs_path = os.path.abspath(event.src_path)
if abs_path.startswith(self.output_dir):
return
run_build(abs_path)
Page frontmatter
Frontmatter is defined in a block comment at the beginning of each index.html file, injected into the page's context during parsing:
<!--
PAGE_TITLE: How this site works
META_DESCRIPTION:
PUBLISHED_TIME: 2025-06-01
-->
<p>This site uses a custom static rendering engine built in Python to parse and generate pages. At its core, it takes in raw markup, parses a block of frontmatter into a combined site and page context, and then outputs templated HTML files.</p>
These injected values can then be used to build out template strings like meta tags or page headings. With index.py files, context can be assigned in the class or imported from defined in an accompanying index.html.
# TODO: Expand these sections
Templating
Template strings and layouts (category pages)
Entry points
Page class
Scheduling
Collections, feeds
Feeds
Based on tags in commit history
Niceties
Minified HTML, quick generate layer, easy expansion
Caveats
Many!