[ Home ] [ Git ] [ Docs ] [ Blog ]

01 - Simple Site Static Generation

Modern web developement is buried in options, even if you are just trying to make a basic website. You can hand write HTML, use static site generators like Hugo or Jekyll, or go all out and write your own webapp in whatever language and framework you choose.

When choosing how to put together the latest iteration of this site, I weighed my options. Generators like Hugo and Jekyll felt too heavy and bloated, raw HTML is annoying and cumbersome, and writing a full web app is overkill. Instead, I looked at how I like to write non-code content.

I use Doxygen for my C libraries, and despite its warts and weirdness I find it pretty pleasurable to use. The translation from comments to HTML documentation is easily integrated into a CI/CD or build process. I also use markdown to write documentation and READMEs, and I knew that pandoc can be used to transform markdown into HTML. So in the general spirit of minimalism, I decided to write a simple site generator using a shell script and pandoc. Here it is in its entirety:

#!/bin/sh

rm -rf static
mkdir -p static

cp -r css static/css

# Landing page
for f in $(find ./content -maxdepth 1 -mindepth 1 -type f -name "*.md"); do
    name=$(echo $f | cut -d '/' -f 3 | cut -d '.' -f 1)
    pandoc -s $f -T burkey.co -H ./html/header.html -c ./css/site.css -o "static/$name.html"
done

# Blog
mkdir -p static/blog
for f in $(find ./content/blog -maxdepth 1 -mindepth 1 -type f -name "*.md"); do
    name=$(echo $f | cut -d '/' -f 4 | cut -d '.' -f 1)
    pandoc -s $f -T burkey.co -H ./html/header.html -c ../css/site.css -o "static/blog/$name.html"
done

# Documentation
mkdir -p static/docs
pandoc -s ./content/docs/index.md -T burkey.co -H ./html/header.html -c ../css/site.css -o "static/docs/index.html"

The directory structure is as follows:

bin/
  gen.sh
content/
  blog/
    index.md
    01-simplesite.md
    ...
  docs/
    index.md
  index.md
css/
  site.css
html/
  header.html

With this basic setup, it’s very easy to modify and extend the static site as needed. As I write more blog posts, they are added to content/blog/. The enumeration of posts is to keep them in chronological order, but is unneccessary if you don’t like it.

The docs/ folder holds a basic landing index page that points to docs for different projects. I mentioned earlier that I use Doxygen for C and C++ projects: their CI/CD process includes generating the documentation and copying it up to my webserver.

css/ holds the css file, and html/header.html is a simple header that goes on the top of every page. Pandoc enforces this with the -c switch for linking the site’s css and the -H switch for pasting the hand-written HTML header into every generated page.

All in all, it’s a pretty simple setup that works really well for me. I use builds.sr.ht to automatically run gen.sh and deploy the HTML output to my webserver. You can check out the build file to get a better idea of how that works.

A Little More Advanced

Since I wrote this post, I decided to add a list of my 5 most recent blog articles. This required tweaking a few things. First, a change to bin/gen.sh:

...
cp -r css static/css

perl $PWD/bin/blog_header.pl >> content/index.md

for f in $(find ./content -maxdepth 1 -mindepth 1 -type f -name "*.md"); do
...

That’s right, we’re going to bust out some Perl. I can hear you screaming in terror already, but Perl is great for text processing when you want to get fancier than awk. The added line above will run the following Perl script and append the 5 last blog posts to the bottom of /index.html

use strict;
use warnings;

my $file = 'content/blog/index.md';
open my $data, $file or die "Could not open file: $!";

my @headers;

while ( my $line = <$data> ) {
    chomp $line;
    if ($line =~ /^\[(.*)\].*/) {
        push @headers, "$line\n";
    }
}

my $limit = 0;
while (scalar @headers > 0) {
    my $val = shift @headers;
    chomp $val;
    $val =~ s/\(([^)]+)\)/(blog\/$1)/g;
    print "+ $val\n";
    $limit += 1;
    if ($limit == 5) {
        last;
    }
}

close $data

I won’t discuss the syntax, but the overall idea is to read in the landing page for the blog, read the lines containing a link to a blog post, and print the 5 newest. My Perl skills are pretty rusty these days, so in no way should you consider this idiomatic Perl.

So there you have it, a minimal way to get a simple site built and generated while writing markdown. No fancy generators, no javascript, just a shell script, a little Perl, and some pandoc magic.