Coding Challenge #77 - Build Your Own Static Site Generator
This challenge is to build your own static site generator like Hugo.
Hi this is John with this week’s Coding Challenge.
🙏 Thank you for being one of the 70,216 software developers who have subscribed, I’m honoured to have you as a reader. 🎉
If there is a Coding Challenge you’d like to see, please let me know by replying to this email📧
Coding Challenge #77 - Build Your Own Static Site Generator
This challenge is to build your own static site generator, i.e. something like Hugo (an open source static site generator built in Go).
Static site generators are a useful tool for those of us who want to build and host a simple, relatively static website. Because the site is static you can easily host it in AWS using CloudFront and an S3 Bucket or on Cloudflare using their Pages. The later is what I’ve done for a new site I’m creating about Programming Project Ideas.
Such static sites are perfect for a simple blog or rarely changing website. No need to run or manage a server and by leveraging the fast infrastructure of AWS, Cloudflare or other cloud providers we can achieve very low latency access - helping with SEO.
You don’t want to see this in your Google Search Console:
And you really don’t want to see any entries in the ‘Poor’ column! Static sites are a great way to ensure you don’t!
But before we get into this week’s coding challenge, some news…
🚨 NEWS! New Live Course! 🚨
I’m re-launching the Coding Challenges Live series beginning with the Redis edition.
It is a cohort based, live, intensive course that runs for one week. During the week you’ll implement a lite version of a Redis server. Starting from scratch we’ll work through building a clone of the original Redis server and extend it to support the RESP2 protocol and some additional commands.
This course touches on a wide variety of topics that are applicable to general programming, for example:
👉 Parsing skills. These can be applied to a variety of problems including data munging, scraping, protocol implementation and more.
👉 Understanding network programming. This can be applied to making more robust, secure and scalable distributed systems.
👉 Experience handling concurrency and parallelism in software. Giving you the core skills to build scalable distributed systems.
👉 Testing. Network servers are complex system software with components that can interact in non-trivial ways. Figuring out how to test them is a challenge. You’ll explore unit and integration testing.
This course is entirely project focused. The goal of the course is not just to learn how to write a server, but also how to approach the problem of server software. Part of the course involves group discussion about problem decomposition, coding techniques, design tradeoffs, testing, and other related topics. The rest of the time is spent working on individual coding.
You might not think that you're ready to write a server, but if you've been coding for a while and know the basics of data structures, it's something that you can tackle. No prior background in network servers is required although awareness of common programming language concepts (e.g., types, functions, classes, scoping rules, etc.) is strongly advised.
If you are a paid subscriber you can get 30% off - please visit the paid subscriber benefits page for the code.
If you are a free subscriber you can get 20% off if you sign up here (code: CCFREE) or you could subscribe now and get the 30% off! 😀
Ok back to this week’s coding challenge…
The Challenge - Building A Static Site Generator
In this challenge we’re going to build a static site generator. It will allow us to:
Create a new site.
Add a new page to the site.
Define some templates.
Run a development server.
Build the static site.
Step Zero
In this introductory step you’re going to set your environment up ready to begin developing and testing your solution.
I’ll leave you to setup your editor and programming language of choice. I’d encourage you to pick a tech stack that makes it easy to launch a web server that can then serve the static website during development or the static website. Go and Python both make this very easy, alternatively you could build your own web server.
Step 1
In this step your goal is to allow the user of your static site generator to initialise a project.
Initialising a project should create a new directory for the project and a basic homepage that they can edit. For the moment this home page can be static HTML with some placeholder headings and text.
In other words the user should be able to do something like:
% ccssg mysite
% tree
.
└── mysite
└── index.html
Where ccssg
is our static site generator. Do feel free to pick a more cuddly name, like Hugo did 😀
Step 2
In this step your goal is to allow a user to create a theme. When a theme is created our site generator should create a directory for themes and within that directory another for the theme itself. Something like this:
% ccsg new theme cc
% tree
.
└── mysite
├── index.html
└── themes
└── cc
└── index.html
Now we can move the content of the index.html to the theme’s index.html. Next up we’ll look at content.
Step 3
In this step we want to start managing the theme and the content separately. That means our new site generator should no longer create an index.html
in the root directory. Instead let’s create a new folder content and within there place an index.md
.
To make this useful we want to be able to add other pages too, so let’s add a new command that allows us to add content:
% ccsg mysite
% tree
.
└── mysite
├── content
│ └── index.md
% ccsg new theme cc
% tree
.
└── mysite
├── content
│ └── index.md
└── themes
└── cc
└── index.html
% ccssg new page about
% tree
.
└── mysite
├── content
│ ├── about.md
│ └── index.md
└── themes
└── cc
└── index.html
We’re starting to create a useful structure now.
Step 4
In this step we want to start making the site useful. Let’s turn index.html
into a template that allows the user to define a generic layout for a page which when rendered by our static site generator will contain the transformed markdown.
For example a template might look like this:
<!DOCTYPE html>
<html>
<head>
<title>
{{ Title }}
</title>
</head>
<body>
{{ Content }}
</body>
</html>
Where Title
and Content
will be replaced when the HTML is rendered by our static site generator.
We now want to support a build command for our site generator. It should go through all the pages in the content directory and render the index.html template replacing the {{ Content }}
tag with the content of the markdown file and the {{ Title }}
tag with the first top level header in the markdown file.
All of this should end up in a new directory called public
. That will look something like this:
% tree
.
├── content
│ ├── about.md
│ └── index.md
├── public
│ ├── about.html
│ └── index.html
└── themes
└── cc
└── index.html
The contents of the public
directory are what we would then deploy to our static website.
Step 5
In this step your goal is to serve a development version of the website. The development version of the website should update when the user edits the content of any of the pages or the theme. This is usually referred to as a livereload.
Going Further
To take this further add support for:
Blogging.
Generating menus.
More tags.
Support for sitemaps and analytics.
Any other features from Hugo and the like that take your fancy.
Two Other Ways I Can Help You:
I write another newsletter Developing Skills that helps you level up the other skills you need to be a great software developer.
I have a YouTube channel sharing advice on software engineering.
Share Your Solutions!
If you think your solution is an example other developers can learn from please share it, put it on GitHub, GitLab or elsewhere. Then let me know via Twitter or LinkedIn or just post about it there and tag me.
Request for Feedback
I’m writing these challenges to help you develop your skills as a software engineer based on how I’ve approached my own personal learning and development. What works for me, might not be the best way for you - so if you have suggestions for how I can make these challenges more useful to you and others, please get in touch and let me know. All feedback greatly appreciated.
You can reach me on Twitter, LinkedIn or through SubStack
Thanks and happy coding!
John