My Design Choices For Websites Generator

Code base screenshot

This is a small blog where I explain some of my design choices for my website generator.
It is also a demonstration of the project itself, since this blog post (and the website you are reading it on) is generated by the tool.


1. Why I Built It

I wanted to learn how static site generators work internally and design one myself, with a focus on:

  • Flexibility -> supporting different site types like blogs, shops, portfolios.
  • Extensibility -> making it easy to add new features through plugins.
  • Clarity -> keeping the codebase small but structured enough to be maintainable.

This project also serves as a portfolio project for my resume, to show my understanding of design patterns and architecture.


2. The Core Abstractions

I designed three main building blocks:

  • Page
    Represents a single page (Markdown, HTML, or other). It holds metadata, content, and output paths.
    I added attributes like slug, page_type, and output_path so the generator can reason about where and how to render the page.

  • Site
    Holds all pages, global metadata, and exposes methods like get_pages().
    This makes it easy to query pages (for example, a plugin can find all pages with type: blog).

  • Project
    Orchestrates everything: configuration, loading pages, running plugins, and rendering.
    By separating "orchestration" (Project) from "data" (Site, Page), the design stays modular.


3. The Plugin System

Instead of hardcoding features like a blog index or RSS feed, I added a plugin system.
Plugins can hook into lifecycle events:

  • after_config_loaded
  • before_build
  • after_document_loaded
  • after_build

For example, my CollectionIndexerPlugin searches for all pages in a collection and automatically generates an index page.

This pattern is common in real-world projects because it balances simplicity with extensibility.


4. Content Processors and Template Engine

To process different input formats (Markdown, HTML, etc.), I added a ContentProcessor factory.
This way, supporting new formats in the future will be as simple as writing a new processor class.

Rendering is done through a Template Engine factory, which abstracts away the underlying templating engine.
This allows swapping templating logic later without changing the rest of the system.


5. Tradeoffs I Made

  • Focused on clarity over optimization -> readability mattered more than micro-optimizations.
  • YAML config -> I chose YAML because it is widely used in static site generators and is more readable than JSON for non-developers.

6. What I Learned

Through this project I practiced:

  • Designing modular, extensible systems.
  • Using factories and plugins to decouple responsibilities.
  • Writing cleaner Python with logging, type hints, and tests.
  • Building something practical enough to showcase.

7. What's Next

  • Add more plugins.
  • Improve test coverage.
  • Deploy this demo site to show the generator in action.