How this site was built
Posted on October 6, 2023 • 6 minutes • 1278 words
Table of contents
Modern tools can make building a website or blog quite easy and painless, especially if you’re willing to accept the out-of-the-box templates and setup. However, when you start wanting things “just so,” the process becomes a little more complicated.
Technologies in Play
For the live site, we have:
- Github Pages
- Giscus
That’s it. It’s a static site published to a Github repository with Github Pages enabled. The post comments are powered by Giscus , an application that integrates with Github Discussions on the repository. These comments are essentially messages within the repository’s discussion section.
How we obtain the static pages that are published:
- Emacs org-mode
- ox-hugo
- Hugo
I create and edit the site content using Emacs org-mode . While this might not be the most common approach, it’s common enough to have a range of excellent supporting tools. Ultimately, the goal in editing is to convert the content into markdown (.md) files for Hugo . Hugo processes these files and generates the static content for the site. Ox-hugo serves as an org-mode “exporter backend” specifically designed for seamlessly transferring org-mode content to Hugo for site generation, which is precisely what I’m doing here.
Where things got a little tricky
The Hugo Theme
Hugo is designed to work with themes and is intended to facilitate the creation, sharing, and distribution of themes. There are many good free and paid themes available to choose from. I tried several different themes and finally settled on the blist theme. It had a clean look that appealed to me and appeared to be quite easy to customize. Additionally, it includes a full “demo site” you can launch right from the theme itself (see the README).
This demo site turned out to be crucial for me, as I was new to Hugo. Hugo looks to a main configuration file where you define options for Hugo as well as custom options to be interpreted by the theme you are using. Each theme does this differently, making it challenging to understand what can be customized and which variables to set for tweaks. This demo site includes a well-structured Hugo config file with all the main customizations for the theme. Studying it a bit teaches you how to create your own customized site.
That being said, even with all that customizability, it turned out that there were still things I wanted to change and tweak that weren’t supported by the theme. This meant that I had to actually learn Hugo and how its templating engine worked, which took some time. Armed with this knowledge, I was able to start adding new variables to the theme itself and setting their corresponding values in the Hugo config. Figuring out how to create new “hooks” in the theme for Hugo and working with how the theme used Sass-compiled CSS took a late night of digging. It was fun to learn and worth the effort, but I just hadn’t anticipated this.
Once I was up to speed on all this, I was able to achieve the desired look.
Getting Github Pages Established Correctly
This wasn’t particularly hard, but it wasn’t immediately obvious where things should be and how to get started. The documentation for Github Pages is good, but there is a lot of information out there, and the first time through, I found it a bit tricky to know where to start. See Where are my Github Pages? .
I had a couple of restarts during this process. I deleted and re-created the repository with a different name (twice), changed the DNS name, and moved the site from residing under a “prefix” in the URL to residing at the “root” of a custom domain, among other things. It was only after I initially got the site up that I started thinking about longevity, search-friendly URLs, SEO, etc. I would have saved some time if I had thought this through beforehand.
The Giscus Comment System Theme
This is a great comment system that’s free to use and piggybacks on Github’s discussion feature. It is also themable, but you might not be able to match it to your layout and color scheme exactly using only the provided customization options. Ultimately, I had to create my own theme file to get it to integrate properly with the rest of my site.
Perfecting the Org-mode -> “fully published” Workflow
Once all the above items were working, I turned my attention to getting text written in org-mode onto the site as quickly as possible. Ox-hugo really does take care of the bulk of the work for me here, but there were still a couple of things to be done.
Reducing image sizes
When taking notes or writing in org-mode, I tend to use screenshots when I need an image. It’s very quick on a mac to grab an area of the screen onto your clipboard (CMD-CTRL-SHIFT-4
) and then paste it right into your org-mode document (with org-download
installed). This relies on pngpaste
behind the scenes
. The issue is that PNGs can be pretty big and I want smaller image file sizes for a static website.
To make this seamless, I wrote a script that converts all the PNGs in the image directory into WebP format. I then created after advice on the org-mode export function to automatically run this script each time I export.
(defun convert-notes-images (&rest _)
(message "Calling convert-images.bb (this is :after advice on org-hugo-export-to-md)")
(call-process "~/org-mode/notes/scripts/convert-images.bb"))
(advice-add #'org-hugo-export-to-md :after #'convert-notes-images)
I’m not actually resizing the images pixel-wise, but this typically results in a 10x + reduction in file size, which is plenty.
Making sure the site works the same locally (hugo serve
) and in production
Special care had to be taken with a few things to make sure I could use Hugo’s built in “local server” to view the site and then also publish it to Github Pages. This will vary depending on your setup, but in my case:
- The
baseurl
in Hugo’s toml config file had to end with a trailing slash (this relates to my custom Giscus theme) - Cross-origin headers had to be setup for the local Hugo server (again related to how Giscus works)
[server]
[[server.headers]]
for = '/**'
[server.headers.values]
Access-Control-Allow-Origin = "*"
Creating a yasnippet for new articles
To make the process of adding a new article as fast as possible, I created a yassnippet to setup new org files destined to be articles:
# key: %org-hugo-blog
# name: org-hugo-blog
# --
#+TITLE: ${1:title}
#+AUTHOR: Matthew Twomey
#+DATE: <`(format-time-string "%Y-%m-%d %a %H:%M")`>
:properties:
#+HUGO_TAGS: vim emacs tooling
#+HUGO_CUSTOM_FRONT_MATTER: :thumbnail /ox-hugo/20231001-161017_screenshot.png
#+HUGO_CUSTOM_FRONT_MATTER: :toc false
:end:
$0
Using this I can start a new article with just a couple of key-strokes.
Making it easy to publish and tracking my changes
The final step was to make sure I could publish to Github Pages quickly and easily. I wrote a script to take care of this. It does a little bit of pre-publication cleanup, runs the Hugo site generation, commits the changes, then pushes to Github. From there, a Github Action takes things the rest of the way and any changes, additions, or updates are live in a minute or two.
I track changes to the source files for the site with git. In the end, there are three different git repos involved:
- My content source (consisting of org-mode files, markdown files generated by ox-hugo, images, assets, ..etc)
- The
public
directory, which is the target directory where Hugo builds the static site (this is what gets pushed to the Github Pages repo) - The theme (the theme I’m using is cloned from git, with my modifications in a different branch so I can pull and merge any updates from the author)