How I Built This Blog
When I expressed interest in creating my own blog, my friend told me about the command line tool Pandoc since she knows I like writing in Markdown. Pandoc allows you to simply convert from one markup format to another, and a common use case is to generate HTML from markup files. She also informed me that it is quite simple to host a static web site with plain HTML using one of the built-in gitlab templates. And then after seeing this video I decided to make my tooling with bash scripts.
My text messages where I first learned about Pandoc are dated February 17 and I made a stable version of the blog that I was happy to share to my friends on March 1. While I have tweaked the blog a little since then, I am comfortable in saying that it took me 12 days to get the blog up and running.
Using a custom domain
First I bought the domain I wanted using Porkbun, a site recommened to me by my sister. Setting up a custom domain with gitlab was simple but a bit fiddly. To add subdomains of your purchased domain, you will need to add A and AAAA DNS records with verify specific Answers/Values; see the following image.

You will notice there were also some TXT records. The TXT
records are added so that gitlab can verify your domain. Using
the project sidebar to access the Pages page and then selecting
“Domains & settings” (or by directly adding
pages#domains-settings to your project home URL).
On this page select the “Add domain” button. Make sure
“Automatic certificate management with Let’s Encrypt” is
selected and add the domain. Then you will need to copy the text
under “Verification status” into a TXT record for that subdomain
and then press the button next to the “Verfication status” text.
Once this is all done press “Save changes”. See the following
images:

After about an hour Gitlab should automatically manage your certificates and allow your blog to be accessed by your custom domains with HTTPS. In the meantime you can access them with HTTP.
Bumby
I called the framework I used to make this project “Bumby.” The framework has an opinionated directory structure:
content/
# contains markdown files that are converted into blog posts,
# the home page, about page, etc. As well as the css that
# styles them and images, videos, etc that any individual page
# may show.
public/
# the static files that gitlab serves as the web site.
scripts/
# A collection of scripts automate boilerplate involved in
# creating and maintaining blog posts, as well as building
# the project.
templates/
# contains Pandoc templates used for this project.
# See https://pandoc.org/MANUAL.html#templates
.gitignore
.gitlab-ci.yml
# Configures gitlab CI/CD.
bumby.sh
# A convenience script for running things from the
# scripts/ directory
README.md
In a linux environment all script actions are performed by executing the following in the project root:
./bumby.sh [action name] [COMMAND LINE ARGUMENTS, IF NECESSARY]For example, if I want to create a new blog post about my favorite anime I would write
./bumby.sh new why-kill-la-kill-is-the-greatest-thing-everThis creates a new directory in content/posts
directory:

.metais a directory containing internal information that the framework uses. The user should never, for any reason, manipulate this directory.mediais a directory that you can use to store images or videos you want to show in the blog post. Or any file that you see fit to using, really.style.cssis loaded by the file which you can use to provide custom styling for the blog post, if you wish. This could prove useful if you write custom HTML in your markdown file, which Pandoc supports. Normally, however, this file is left empty.<blog-title>.md is the markdown file that Pandoc will convert into the HTML for the web page representing this post.
Every blog post is stored in a directory with a name like
XXXXXX-blog-title. This was so that the order of
blog posts was determined by the order of the files when they
are globbed. The files in a glob are ordered lexicographically
meaning that 2-blog-title would come after
147-blog-title, hence the six-character number
prefix for each directory in my framework. (This has the
unfortunate consequence that the framework will cease
functionality if a million blog posts are made. Might make for a
fun challenge.)
The title used in the directory name and markdown file must
be dasherized and only contain numbers, letters, underscores,
and dashes. This was to simplify the code I had to write.
Furthermore, the markdown file in the directory must be the
title that comes after the numeric prefix in the directory name.
If I changed
why-kill-la-kill-is-the-greatest-thing-ever.md to
why-i-love-kill-la-kill.md then the build script
would not function. Hence I introduced a helper for editing
pre-existing blog posts. For example, I could do
./bumby.sh edit why-kill-la-kill-is-the-greatest-thing-ever \
why-i-love-kill-la-killThis would change both the directory name and markdown file simultaneously.
The name of the markdown file is also the url associated with
the post. For example, the post shown in this example would be
located at
https://bumbyskitchen.clodsire.social/post/why-kill-la-kill-is-the-greatest-thing-ever.
Let us view the content of
why-kill-la-kill-is-the-greatest-thing-ever.md.

To understand how this markdown document is handled, let us build the project by running
./bumby.sh buildThis creates the following in a directory called
dev in the project root:

We can open
why-kill-la-kill-is-the-greatest-thing-ever/index.html
in any web browser to see how the blog looks so far:
Evidently the text after title: in the markdown
document determines the title shown in the web page. Also notice
that it determines what is shown in the browser tab. While, by
default, it is a space-separated and capitalized version of the
name of the markdown file, you are allowed to change this title
to whatever you wish.
In addition to the title you should also provide a summary:

This summary is displayed by any RSS reader which is tracking the blog. With all of this setup we can begin writing the blog content:

For more immediacy, I implemented a watch mode that will
automatically rebuild the project when changes to the
content or template directories are
detected. This is done with the --watch option:
./bumby.sh build --watchWhen writing new blog posts I build the development version of the blog in watch mode exclusively.
The essentially demonstrates the workflow that I have
established for myself with Bumby. The only things of
significance I did not show is that you can write mathematics
with LaTeX code and this show up in the blog post in the ways
you would expect if you have used LaTeX before, and how the
build script is used in .gitlab-ci.yml to generate
the files in public.
More development details
- The
templatesdirectory contains all Pandoc templates used by Bumby. It mostly contains boilerplate HTML surrounding blog posts, but there is some interesting use of conditional templating that Pandoc supports. This is used, for example, to determine whether the “Next” and “Last” icons at the bottom of the blog post are shown (the last blog post does not have them). - While my templates have code that imports a CSS file directly, Pandoc actually supports providing a CSS file to an invocation that is then added as style tags in the output HTML. This would have been simpler than manually copying the style files but I only noticed this functionality after I had already implemented it.
- The most robust mathematical parsing Pandoc supports is with
Mathjax, a wonderful JavaScript library that converts Latex code
to mathematics. However, I was interested in creating a site
avoids any JavaScript usage at all, and I noticed that Pandoc
has an option for using the CodeCogs API to generate
svgs representing your equations. Pandoc will create HTML with
imgtags whosesrcattributes use the CodeCogs API. However, I didn’t want my blog to be fully dependent on CodeCogs, so I have some logic in my build script that, after the files are generated, parses the HTML to find allsrctags which use the CodeCogs API and then download the images manually to the media directory associated with the post. Then, the script replaces the URL in thesrcattributes with file I just downloaded. This way, if CodeCogs goes down after my blog is published, the math in my blog will remain intact.
Why bash
After finishing the project I came to the conclusion that I would not have used bash if I could do it all over again. I used Bash simply because the video I saw which used Pandoc to create web pages used the fish shell script. Their code was very simple so I assumed that my code would also be simple.
It ended up not being simple. At the time I write this sentence I have nearly 1200 lines of shell scripting in my project.

I can say from experience that Bash does not scale well for large projects. Going into detail about why I feel that way is a blog post of its own. That being said I did enjoy my time with Bash. I like dynamically-typed interpreted languages and the pipe syntax is fun to use even when it creates ugly code. Since WSL comes with Windows now bash scripts are mostly portable. I will happily use it again for simpler use cases in the future.
My sister told me that Make would have been a very good choice for this project. She is probably correct. In fact, her annoyance that I made my job harder myself inspired her to write a blog of her own with Make (and sblg)!
However, I like seeing things through. I like writing tools by hand. I like understanding how libraries work and why they were made. I am infinitely more satisfied with the project I wrote as it is, much more so that I would have been had I used some preexisting static blog generator.
Anyway, that’s as much as I feel like writing on how I made this blog. It is late so I will not fix the bug with the “last edited” text until later.