I wrote a new thme for my blog. YAY!
DISCLAIMER: This is not a HOW TO, just my thoughts.
Okay, let’s be real. I don’t even think it’s any better than what I had before. But there is one slight difference. I CREATED THIS. I didn’t copy and just modify it. I took something and created from scratch.
This blog is stil built on Hugo, but the theme is a lot simpler. I did use tailwind to make this, just because of how good it is and how bad I am at CSS. So here are some of the fun details about making this change and really, just my thoughts on Hugo and tailwind.
Hugo is great
I have been using Hugo on this blog from the start. I had a few criteria when I selected something to use for my blog:
- It had to be fast.
- It had to be easy to set up.
- It had to take Markdown as the source for my content.
- Bonus points for no JavaScript.
And Hugo checked all of those boxes. It’s blazingly fast—literally instant. It was very easy to set up. It compiles down to a single binary that I just install, and I don’t have to worry about Node or Python versions or anything like that.
There are a lot of themes to select from. It was harder to select one than to install it. Because install is literally adding a git submodule (which is kinda weird, but works very well) and setting the theme in your config.
It works with Markdown: just create a file in content/posts using the hugo new content command, and you can start writing.
And it was nice, but I kinda wanted to make my blog even more minimal. Just some white text on a dark background. So I set out to create my own theme. And boy, was it interesting.
Hugo templating is a bit confusing
Hugo works by taking your Markdown files and applying layouts to them. It reminded me of Blade templates from the time I used Laravel, except this uses the Go templating engine, aka html/template. It has the vibe of Blade templates, but, well, not quite as nice. I find the syntax ugly and hard to read, but once you get used to it, it’s not that bad.
So, I went ahead and tried to create my templates. Creating the base was simple: just drop a layouts/_default/_baseof.html, throw in some HTML, and add a {{ block "main" . }} in the middle of it.
But then you have to learn a whole magical ordering of how templates are picked up. And the docs take a bit of time to understand here. Then you need to understand the ways how files are even picked up, and how that displaying a list of posts on your homepage is a whole deal. It might be a skill issue, but it took me longer than I wished.
But once I figured out which file is which, it was smooth sailing. Kinda.
Hugo has some pains
One issue I ran into that I never had before is that Hugo didn’t want to pick up on already created files. To explain it, I have homepage with one sentence and list of posts. BUT IT WOULDN’T SHOW THE POSTS. Unless I go to the post save it, and then it would be picked up.
So that was annoying, otherwise it was smooth sailing.
Tailwind is great
And everyone (kinda) knows it. I wanted to use it. I thought it might be a pain, since I’ve only used it with React. But it turns out it’s pretty easy.
I just needed to do the usual install, modify the config to look for my layout files like this:
module.exports = {
content: ["./layouts/**/*.html", "./content/**/*.html"],
...
}
and then run
npx tailwindcss -i ./assets/css/main.css -o ./assets/css/out.css --watch
And it just worked. Until I didn’t know how I could style the content, since it’s just blob of formatted html.
Tailwind plugins to the rescue
Turns out there is a plugin for this. Called @tailwindcss/typography and it
worked just fine. Just needed to add class="prose" where I had my text.
{{ define "main" }}
<div class="flex justify-center p-10">
<h1 class="text-3xl font-bold">{{ .Title }}</h1>
</div>
<div class="flex justify-center">
<article class="prose lg:prose-lg dark:prose-invert">{{ .Content }}</article>
</div>
</div>
{{ end }}
And it was that simple. The smart people at tailwind have provided all the good
styling for this out of the box. No need to worry about wrong font sizes, or
colors or whatever else you need to do. I just wanted to make it bigger so it’s
easier to read. Which worked easily with tailwind magic lg:prose-lg
It also crashed
TWICE
Rebuilding...
Done in 112ms.
<--- Last few GCs --->
[100790:0x710d570] 1502531 ms: Mark-Compact 4008.4 (4132.7) -> 4002.8 (4143.5) MB, 1415.12 / 0.00 ms (average mu = 0.708, current mu = 0.183) allocation failure; scavenge might not succeed
[100790:0x710d570] 1504851 ms: Mark-Compact 4018.5 (4143.5) -> 4013.0 (4154.5) MB, 2295.04 / 0.00 ms (average mu = 0.452, current mu = 0.011) allocation failure; scavenge might not succeed
<--- JS stacktrace --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0xc9adf0 node::Abort() [node]
2: 0xb700f7 [node]
3: 0xec0530 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
4: 0xec0817 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
5: 0x10d1ea5 [node]
6: 0x10e9d28 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node]
7: 0x10bfe41 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
8: 0x10c0fd5 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
9: 0x109e546 v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [node]
10: 0x14f9376 v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [node]
11: 0x72af72e99ef6
Aborted (core dumped)