Introducing BLASH
Backstory
So I wanted to start blogging. The first thing I needed was a place to put all the stuff into — well, GitHub Pages does exactly that, I guess that’s one thing less to worry about. Now, GH Pages uses Jekyll, which is a static site generator, which is great because it means I do not have to worry about databases and plugins and all that kind of nonsense, if I ever need to backup the blog I can just rsync
everything and call it a day.
But… I don’t like Jekyll. It’s written in Ruby, and that makes it a real pain in the proverbial to use under Windows, but I don’t like having to install the Ruby runtime on Linux either. Also, I don’t really like being forced to use Sass and CoffeeScript or the Liquid template language. This means I have to search for another generator.
Maybe Hugo? Too complicated, I don’t really want to spend that much time configuring it to make my blog look the way I want it to. (In hindsight, this is quite ironic: I could probably have spent less time configuring Hugo than writing BLASH but…)
Introducing BLASH
What I wanted was something really flexible yet simple to configure (or at least intuitive… for me) and with very few dependencies.
The last point made bash
a very obvious choice, as it is available on basically any system nowadays - even Windows has it via WSL. The only other dependency is on Pandoc.
How does it work?
BLASH can be configured using shell files. Whereas Jekyll uses YAML front-matter, BLASH uses a separate shell script for each blog post, in which information like the title, tags and author are stored.
For example, let’s say you want to create a blog post titled Hello world
: you’ll create two files:
2018-11-12-hello-world.sh
2018-11-12-hello-world.md
The shell file will contain something like this:
#!/bin/bash
title="Hello, world!"
author="Jane Doe"
excerpt="Lorem ipsum dolor sit amet"
tags=("hello-world" "foo")
While the Markdown file will be your standard content, ready to be converted to HTML by Pandoc.
Templates work in a similar way, as they are shell scripts too. Let’s take a look at a simple template (post.sh
):
#!/bin/bash
year=${date:0:4}
source="<!DOCTYPE html>
<html lang=\"en\">
<head>
<meta charset=\"UTF-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">
<link rel=\"stylesheet\" href=\"$base_url/assets/css/stylesheet.css\">
<title>$title</title>
</head>
<body>
<header>
<h1>$title</h1>
<h2>$excerpt</h2>
<h3>By $author</h3>
</header>
<main>
<article>$content</article>
</main>
<footer>
<p>Copyright © $year $author</p>
</footer>
</body>
</html>"
This file will be read once for every post, each time with different values in the variables. Of course, it’s a shell script, so you’re not limited to string expansion.
BLASH will also take care of generating the various indices in your blog: the main one, one for every tag and category, and one for every date. It uses a single template for every kind of index, index.sh
:
#!/bin/bash
content=""
for post in "${posts[@]}"
do
post_title=${titles[$post]}
excerpt=${excerpts[$post]}
date=${dates[$post]}
url=$(fileNameToUrl $post)
content+="<li>$date - <a href=\"$base_url/$url\">$post_title</a> ~ <em>$excerpt</em></li>"
done
subtitle=""
if [ -n "$tag_name" ]; then
subtitle="Browsing posts by tag: <span class=\"tag\">$tag_name</span>"
fi
if [ -n "$category_name" ]; then
subtitle="Browsing posts by category: <span class=\"category\">$category_name</span>"
fi
if [ -n "$date_span" ]; then
date_span=$(sed 's/\//-/g' <<< "$date_span")
subtitle="Browsing posts by date: <span class=\"date\">$date_span</span>"
fi
source="<!DOCTYPE html>
<html lang=\"en\">
<head>
<meta charset=\"UTF-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">
<link rel=\"stylesheet\" href=\"$base_url/assets/css/stylesheet.css\">
<title>$title</title>
</head>
<body>
<header>
<h1>$title</h1>
</header>
<main>
<ul>$content</ul>
</main>
<footer>
<p>Copyright © $current_year $default_author</p>
</footer>
</body>
</html>"
tag_name
, category_name
and date_span
will have different values depending on the index type that’s being generated.
Finally, general configuration of the blog is done via the config.sh
file:
#!/bin/bash
: ${blog_title:="Francesco Bertolaccini's blog"}
: ${default_author:="Francesco Bertolaccini"}
: ${base_url:=""}
configureAssets () {
for css in assets/css/*.css
do
filename=$(basename -- "$css")
cp "$css" "publish/assets/css/$filename"
done
}
configureAssets
will be called once every time the site is built. You can put your css/js minification in there, for example. The weird variable syntax is to allow override in the command line.
To summarize, this is the general directory tree:
website
|- assets
| |- css, js, images...
|
|- contents
| |-posts
| |- 2018-11-12-hello-world.md
| |- 2018-11-12-hello-world.sh
|
|- templates
| |- index.sh
| |- post.sh
|
|- config.sh
|- publish.sh
So, how do you build the site?
./publish.sh $
Done. The command will put the resulting artifacts into the publish
subdirectory, and those files will be ready to be sent to a server.
You can also override variables if you want:
base_url=/foo ./publish.sh $
Conclusion
This is working well for me so far — that is, one post — but I’m convinced it’s simple and flexible enough for me to keep using it, I hope you’ll like it too :) You can find it on github: BLASH!