How I built my personal website

Lucca RodriguesJune 16, 2021

programming meta web design

Note: this guide is outdated. You can find more up-to-date meta-articles here.

This is a little guide for those who might be interested in knowing how The Lucca Logs was made and my reasoning behind some of the design choices that I made while building this website.

All files and source code for my website are available on GitHub. If you’re looking to use any part of this website’s code in a project of your own, you can find a more straightforward and easier to follow guide here.

Now buckle up, dear reader, because this post is quite a lengthy one. I’ve included a table of contents for your convenience.

Table of contents

A brief introduction

To be perfectly honest, I don’t have any experience at all when it comes to building websites. I’ve never tried services like Squarespace, Wix or Wordpress, and I’ve yet to try using a “real” static website generator like Jekyll or Hugo, but I’ve heard that these tools/services can yield some pretty nice results. In fact, a good friend of mine who’s also a programmer uses Hugo on his personal website and it ended up looking very unique and quite spiffy!

But instead of diving straight into learning how to to use some sort of website making tool, I wanted to try building something that was truly my own. I wanted something that had just the right balance of control and expandability - something that I gave me almost complete control over my website, but at the same time would give me the flexibility to add libraries and extra features as I saw fit. Or in other words, I basically wanted to build my website (both frontend and backend) from scratch.

I have some experience building basic full-stack web applications with Node.js, but no experience so far with frontend libraries like React, Angular or Vue. Naturally I chose Node as my backend and I decided to write all of the frontend stuff in plain HTML, CSS and JavaScript.


My vision

Content-wise, I wanted a reasonably simple website for displaying a couple of blog-style posts in which I could talk about anything to my heart’s content: music, coding, science, technology, you name it.

I wanted to build a system that made it ease for me to write new posts without having to mess around with complicated databases, preferably by only creating/editing a single plaintext file. Extra libraries (both frontend and backend) had to be kept to a minimum to reduce complexity. Any extra NPM packages or frameworks better have a really good reason to consume any extra space on my hard drive.

And for whoever might be consuming content on this website, I wanted them to be greeted with something that was minimalist in nature to avoid distractions, but still somewhat aesthetically pleasing. I also wanted to build something that made it easy to browse posts and topics easily and quickly, in the case that the reader wished to do so.


The solution

To meet these goals, I came up with the following system.

My website uses a custom-built static site generator (What’s that?) which takes in plaintext files with post content and metadata, adds some CSS templates, and generates all of the HTMLs for the website. The generator is a (reasonably) simple script written in JavaScript that runs in Node.js. The files are served by a Node.js + Express static file webserver. All of the static files and the webserver are hosted on a basic AWS Lightsail instance running Ubuntu 20.04, which costs a meager $4 USD/month to run. I’ve also set up a CI/CD pipeline with GitHub Actions for automatically building and deploying my website to AWS, which you can read more about here.

Note: I’ll be often referring to the static site generator as a “compiler”, because that’s just the name I chose for the script -compiler.js” - and because it does sort of act like a compiler by “compiling” the posts into actual webpages.

Even though Express.js is quite a chonky Node.js library, it’s by far the simplest web framework I’ve ever used. It’s ridiculously easy to use, and I love how trivial it is to setup Express as a static file server and to create custom routes.

Unpopular opinion/Digression: Django’s “all batteries included” approach quite honestly sucks and is very alienating for beginner web developers (like myself), even if you’re an intermediate Python programmer with a couple of years of experience under your belt (…like myself). You’ll quickly find yourself constantly switching between a huge amount of additional (read: unnecessary) files, even if all you want to do is setup a minimal webserver. Flask and Express.js did it way better - change my mind.

As far as the actual posts go, I chose to go with Markdown (.md) files which contain both metadata in YAML and actual text content written in Markdown. The compiler script splits the file in half and parses the YAML with JS-YAML to extract the metadata and the actual text with Marked.js to convert Markdown into pure HTML, which can be rendered by a web browser.

Markdown makes it super duper easy to write nicely formatted text with headers, section, subsections, links, images, etc. It’s much less cumbersome than raw HTML and writing and formatting text-based content, but since it can’t be rendered by a browser, it needs to be converted to HTML somehow first, which is where Marked.js comes in.


Creating posts

New posts are created by simply creating a new Markdown (.md) file in a specific directory and populating it with:

After running the compiler, something like this will be generated, written to an HTML file and will be ready to served by the Node.js webserver:

image

Not bad, right?

After the post was generated and deployed, readers can view it by visiting mywebsiteurl.net/post-name.

Notice how the title is clearly displayed at the top with a big, readable font and a horizontal line that makes it stand out from the rest of the post. The date in which the post was made and groups in which the post belongs are neatly shown under the horizontal line in unobtrusive italicized text with a gray color.

This system certainly accomplishes the goal of making it really easy to write and update posts, but I think the true beauty comes from the fact that all the information is neatly stored in a single human-readable plaintext file rather than a database or some other obscure format.


Templates

The compiler has a basic templating engine in the form of stylesheets and Markdown/HTML content templates.

Templates can be applied to a post by specifying the template’s filename in the templates list in the post’s front matter. The file needs to be located in the project’s /public/templates/ directory (check example below).

By default, two base templates called base.html and base.css are included with every single page. Pages for displaying posts in a specific group also include the group.css template (more on that in the “Groups” section below).

I even made a nifty template for fetching GitHub READMEs! You can see it in action for yourself here. Now I don’t have to redo my old project write-ups! 😄

---
templates: [github-fetch.md]
groups: [all, github-readme, me]
github-url: https://github.com/ChromeUniverse/Personal-Website 
date: 2021-05-27 14:33:00
---

In the example above, the base.html, base.css and github-fetch.md templates will be included with the post.


Groups

”Groups” basically work like tags for the posts.

Posts can be filtered by groups by simply visiting mywebsiteurl.net/group-name, which will display all posts that belong in the group group-name, sorted from newest to oldest. For example, if I wanted to see all posts that belong to the “music” group, I would go to mywebsiteurl.net/music.

Groups are assigned to posts by specifying which groups that post should belong to in the groups list in the post’s front matter.

title: My thoughts on Daft Punk's _Random Access Memories_
templates: []
groups: [all, album-review, music, daft-punk]
date: 2021-05-27 12:00:00

The example post above would show up in the all, album-review, music and daft-punk groups.

Description

The post’s author can specify a description for the post in the YAML front matter. The description’s text will be displayed in group page previews and will appear on the post page’s <meta name="description" content=""> tag.

title: My thoughts on Daft Punk's _Random Access Memories_
templates: []
groups: [all, album-review, music, daft-punk]
description: |
  My review of Daft Punk's 2013 full-length LP, Random Access Memories.
date: 2021-05-27 12:00:00

In the example post above, there’s a short summary about the post’s content: “My review of Daft Punk’s 2013 full-length LP, Random Access Memories”.


The static webpage generator

My website generator (“compiler”) is quite limited in what it can do, but it’s the one doing the heavylifting behind this website. It gets the job done, and it’s proven to be quite easy to maintain and expand on. It’s a relatively simple Node.js script which I have set up to run using nodemon. Nodemon watches for changes in post files and template files and re-runs the compiler on every file save.

This is how it works:


Conclusion

Writing these posts and building the infrastructure for this website have both been very time-consuming and quite the adventure, but honestly, I think I’ve done a pretty acceptable job, regarding the quality of both the actual content and the underlying programming. Creating and editing new posts is now an effortless process, group pages are generated automatically by the compiler, and my automated integration and deployment pipeline is working flawlessly. I’ve also grown quite fond of Markdown and YAML during the making of this project.

I truly believe my current setup for maintaining this website is a viable solution for a personal blog-style website such as my own. And no, I don’t mean it’s complete by any stretch of the imagination - there’s still a lot of work to do and loads of features to add. But I’m certain it has the potential to create websites which are aesthetically pleasing and minimalist in nature, yet still very functional and expandable.

Hopefully people can see what this system is capable of and will adapt it to their own use cases, or at least learn a thing or two from my ongoing web design adventures.

And it turns out that this project also helped me realize that I actually really enjoy writing! This project was a surprisingly enjoyable way to combine my programming skills with writing, and I never thought creating a personal blog could be this fun. I can totally see myself writing posts for the remainder of this year, at least.

For the time being, this is all I have to share about my website. If you’ve made it this far, thank you soooo much for reading this - I’ve put a lot of effort into making all of what you see right now.

Have a good one! Lucca out. 👋