Welp! It was time! Time for a big website refresh. Let’s talk through it.
2017 - 2024: Tech debt 😱#
As a reminder, the previous version of this website was:
- originally written in HTML + CSS + a touch of Javascript, with just a few html pages (
about.html
,scifi.html
, etc.) - a static blog generated by Pelican
- using a special Pelican theme on an outdated fork
- modified to match the CSS of my original, manually-written HTML + CSS…
So I would use Pelican to generate the entire website, but I basically had everything spread out over four (4!!) directories/repos, and it was an awful pain to maintain. This was how things had been going since 2017. And it was just very very tech debty.
2022: Thinking about Hugo 🤔#
I had heard good things about Hugo, and thought it might be fun to try rewriting the blog in Hugo. This was back in 2022. I tinkered a bit, but then life got busy again and I dropped it.
2024: Moving to Hugo ⛵#
I picked it up again, found a theme I liked (Blowfish), and decided to commit! This was a couple weekends’ worth of work.
1. Quickstarting Blowfish with a bare Hugo site 🐡#
As a first step, I followed the Blowfish tutorial to get a basic site up. Nothing special here.
2. Converting my Pelican blog to Hugo 🐦#
I had about ~100 blog posts that needed to get Hugo-fied. I wrote a short Python script to rewrite their Markdown just a touch, mostly the frontmatter and relative references.
def process_file(
filepath: str,
read_dir: str = INPUT_DIRECTORY,
write_dir: str = THIS_DIR,
verbose: bool = False,
) -> None:
if verbose:
print(f"Now doing {filepath}")
with open(f"{read_dir}/{filename}", "r") as f:
lines = f.readlines()
frontmatter = []
body = []
in_frontmatter = True
subdir = None
for line in lines:
if in_frontmatter and re.match(r"^\w+:\s.*", line):
key, value = map(str.strip, line.split(":", 1))
key = key.lower()
value = value.replace('"', "'")
value = value.replace(":", "-")
if key not in VALID_PELICAN_KEYS:
continue
if key == "date":
value = format_date(value)
elif key == "tags":
value = [str(tag.strip()) for tag in value.split(",")]
elif key == "category":
if len(value) > 0:
value = [str(category.strip()) for category in value.split(",")]
elif key == "slug":
fpath = f"{write_dir}/{value}"
if not os.path.exists(fpath):
os.mkdir(fpath)
subdir = value
elif key == "summary":
value = f'"{value}"'
frontmatter.append(f"{key}: {value}\n")
else:
in_frontmatter = False
if "```{" in line:
line = line.replace("```{", "```")
line = line.replace("}", "")
if "{static}" in line:
line = line.replace("{static}", "")
if "img" in line:
img_filename = re.findall(r"\((.*)\)", line)[0]
if "https" in img_filename:
if verbose:
print(img_filename)
continue
# kinda hacky
img_filename = img_filename.split("/")[-1]
fpath = f"{write_dir}/{subdir}"
if img_filename in os.listdir(fpath):
print("Already here")
else:
os.rename(
f"{IMGS_DIRECTORY}/{img_filename}", f"{fpath}/{img_filename}"
)
line = line.replace("imgs/", "")
body.append(line)
In short, tons of string parsing - including some dreaded regexing. My workflow was mostly:
- Ask ChatGPT for boilerplate
- Try out regex in regexr
- Tons of print statements to debug {chefs kiss}
- Sit at cafe and think about the state of the world.
3. Just do the whole website in Hugo actually 🐡#
Namely, the static, non-blog pages, like scifi. This just took some understanding of how Hugo configs work.
4. Deploying 🚀#
I deploy this site manually, just SCPing the files over to the server where it’s being hosted.
scp -r public/* $WWW_USERNAME@$WWW_IP_ADDRESS:~/public_html/
Tadaaaaa! 🎉
80/20 it 😅#
You may have noticed that some of the writing doesn’t show up, and the colors are a bit weird, and I think I still have draft posts sometimes showing up. Sigh.
Anyway, I kept telling myself: 80/20, 80/20, 80/20. So I’m keeping a running list of things I’d like to fix or polish, but the main website is up and running - and that’s what matters!