Building a simple static website

Published on 2024-11-20

I was tired of looking from the marketing of static website generators, and thought that it would be a great occasion to create one just for myself. After all, I probably don’t need 99% of the features of the latest frameworks.

The goal is pretty simple:

With no further words let’s see how to do that.

Markdown conversion

For the markdown to html generation, we want to use pandoc:

# On Mac
brew install pandoc

# On Ubuntu/Debian
sudo apt-get install pandoc

We’ll create this project structure, with our content on the src folder, and the generated files in the public folder, ready to be distributed.

alexisfabre.fr/
├── src/
│   ├── index.md
│   ├── resume.md
│   └── articles.md
├── public/
├── metadata.yaml
├── template.html
└── convert.sh

The convert.sh file will be the one to run when we want to regenerate our content:

#!/bin/bash

# Create public directory if it doesn't exist
mkdir -p public

# Convert all markdown files to HTML
for file in src/*.md; do
    filename=$(basename "$file" .md)
    pandoc "$file" \
        --template=template.html \
        --metadata-file=metadata.yaml \
        -o "public/$filename.html"
done

With that, we can use a general metadata.yaml file and a template.html in which we’ll put the body from our markdown files:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>$title$</title>
    <style>
        body { 
            max-width: 800px; 
            margin: 40px auto; 
            padding: 0 20px; 
            font-family: sans-serif; 
            line-height: 1.6;
        }
        nav { margin-bottom: 2em; }
    </style>
</head>
<body>
    <nav>
        <a href="index.html">Home</a> |
        <a href="resume.html">Resume</a> |
        <a href="articles.html">Thoughts</a>
    </nav>
    $body$
</body>
</html>

Here we can see the $title$ and $body$ variables. The former can either come from the metadata.yaml file or the markdown files header directly. The latter is the direct content of the markdown files. Here is an example for index.md with a header including the title variable:

---
title: Home
---

# Welcome to my website

This is my personal corner of the internet.

Now we can give permissions and execute convert.sh:

chmod +x watch.sh
./watch.sh

See our files generated in public:

alexisfabre.fr/
├── src/
│   └── index.md
├── public/
│   └── index.html
├── metadata.yaml
├── template.html
└── convert.sh

Running the web server locally

We can easily set up a local web server using python http.server module:

python3 -m http.server

The files will be available at http://localhost:8000.

Hot rebuild

We want the conversion to be executed everytime we save our source or template files. For this we will use entr, a file watcher utility tool:

# On Mac
brew install entr

# On Ubuntu/Debian
sudo apt-get install entr

The following script will watch for changes and automatically call convert when you save a file in src or template.html:

#!/bin/bash

# Start the Python HTTP server in the background
cd public
python3 -m http.server 8001 &
SERVER_PID=$!

cd ..

# Watch for changes and rebuild
find src template.html | entr -s './convert.sh'

# Clean up the server when the script is interrupted
trap "kill $SERVER_PID" EXIT

Note that it will run in port 8001 so we still have our web server at port 8000.

Give permissions to execute and run the watch.sh script:

chmod +x watch.sh
./watch.sh

Conclusion

This was a great exercise to learn more about static website generation and file watching. I’m sure I’ll use this setup again in the future.