A cookie with a bite take out of it surrounded by angle brackets.

Bytes and nibbles

By Samuel Matsuo Harris

linkedin

Home

Bytes

A cookie with a bite take out of it surrounded by angle brackets.

Nibbles

How I made this website for free

I wanted to blog, but not quite enough to shell out money

Building the bytes and nibbles website

Published: Sat, 06 Apr 2024

Last modified: Sun, 28 Jul 2024

How I made this website for free

Introduction

This is the story of how I made this whole website for absolutely no cost, from beginning to end.

The code for this website can be found at https://github.com/Samuel-Harris/Bytes-and-Nibbles-Website.

The code for the Content Management System (CMS) can be found at https://github.com/Samuel-Harris/Bytes-and-Nibbles-CMS.

Fleshing out the problem

Taking inspiration from Amazon’s working backwards method, I started by identifying the problem and what I needed to solve it. My problem was that I wanted to work on more AI in my spare time. I decided that starting a tech blog would be a great way to encourage myself to do this while sharing the interesting things that I make with you, my beloved readers! I also love cooking and hate having to read recipes from a range of differently formatted recipes, so I decided to include recipes that I liked in this website.

For my tech blogs, I decided that I wanted the following features:

  • Free
  • Ad-free
  • Tech blogs
    • Paragraphs
    • Images
    • Markdown support
    • Custom TypeScript code execution (e.g. for WebLLM chatboxes)
    • more details sections that are hidden by default, but can be toggled to expand and reveal their contents
    • Email subscriptions
    • Automatically generated list of published blogs
  • Recipes
    • Ingredients
    • Steps
    • Cover photo
    • Cooking time
  • Headless Content Management System (CMS)
  • Authentication in the CMS
  • Authorisation in the CMS
    • Admin user type (me) for writing blog posts
    • Regular user type

I then narrowed these down to form the Minimum Viable Product (MVP) features:

  • Free
  • Ad-free
  • Tech blogs
    • Paragraphs
    • Images
    • Markdown support
    • Automatically generated list of published blogs
  • Recipes
    • Ingredients
    • Steps
    • Cover photo
    • Cooking time
  • Extensibility to support any client-side features I may want in the future
  • Headless Content Management System (CMS)
  • Authentication in the CMS
  • Authorisation in the CMS
    • Admin user type (me) for writing blog posts
    • Regular user type

Most of these are self-explanatory, but one of the key features that deserves some explanation is the requirement of a headless Content Management System (CMS). A CMS is software that allows users to manage the content of a website without having to code. It is a solution that handles the storage and rendering of content without extra code needing to be written to create and render content, which would make writing blogs far easier for me. A headless CMS is a CMS that has an API but no built-in frontend, so the frontend and the backend are completely decoupled. The reason why I chose this type of CMS was because if I ever wanted to change the frontend or backend, I could easily swap another frontend or backend in, preventing vendor lock-in.

Choosing the tech stack

I could have chosen an existing solution, such as WordPress, or the Medium/toward data science, but I decided not to due to concerns about cost, ads, and the customisability of these solutions. I wanted it to be completely free to run because I’m stingy, and I didn’t want any advertisements on my blogs because I hate seeing ads in the content I consume, so I wouldn’t want to make others suffer through them. Customisability was also key to ensuring that I could implement any features that I might want in the future.

To choose my tech stack, I started by researching hosting options. I noticed that my features didn’t require a particularly complicated backend, so I decided to opt for a hosting service that offered Backend as a Service (BaaS) to reduce development time.

The two options I found that fit my criteria were GitHub Pages and Firebase with the spark plan. I decided to use Firebase because GitHub Pages seems limited in extensibility and features, and would be difficult to integrate with a CMS.

Next, I chose FireCMS for the CMS because it was easy to integrate with my CMS backend, provided an out-of-the-box UI for managing the content, and allowed custom rendering of UI components if I ever needed them.

Finally, I decided to use TypeScript, React, NextJS, and Jest for the frontend. This was primarily because of my familiarity with the frameworks and my preference for TypeScript over JavaScript. I wanted to spend as little time developing the frontend while keeping it extensible and customisable, which is why I chose these technologies based on familiarity, as unfamiliar technologies introduce steeper learning curves.

Implementation

The implementation was time-consuming, but relatively straightforward. I started by designing the file schema for the tech blogs, which I decided to call “Bytes”, and recipes, which I decided to call “nibbles”. I was very proud of coming up with the name Bytes and Nibbles for this website, and I hope you enjoy the name as much as I do.

After designing the file schemas for the bytes and nibbles, I implemented the CMS before implementing the frontend content renderer. EDIT: Previously, I had not released my CMS code due to security concerns. After being begged to release the code by a persistent friend, I have removed the sensitive authorisation rules configurations, and made the CMS code available here. The frontend code is also available here.

While adding dynamic routes for the bytes, I discovered that when building statically, Next.js’s dynamic routes must also be statically generated. This meant that all of the routes needed to be known at build-time. Since there is a unique path for each byte or nibble, this means that only the bytes and nibbles known at build time can be shown. I am the only one making bytes and nibbles, so this is acceptable as it is not difficult for me to build and redeploy the site whenever I write something (which won’t be often). This also meant that I needed to change my byte listing page to be generated statically at build-time instead of being fetched dynamically when a client accessed the bytes list page to ensure that the listed bytes and nibbles always reflected the accessible bytes and nibbles.

I also chose to add a CI/CD pipeline with GitHub actions to automate deployment, testing, and linting because I just know I’ll forget to do these things when making pull requests.

Conclusion

I am very proud of this website and plan to use it for years. The CMS is decoupled from the content rendering, so changing either in the future should be relatively simple. It does require me to rebuild the site every time I release a byte or a nibble, but that’s a small inconvenience to me as it can be done with one click using a GitHub action.

The next steps for this website are for me to primarily focus on writing content for it. I will add extra features to the blog as and when I need them, but I do not have any plans to do so for the foreseeable future.