Skip to content

Repository files navigation

Blougly

An ugly static site generator that gets out of your way.

Requirements: PHP 8.3+ · Composer 2 · License: MIT · Contributing: CONTRIBUTING.md

What it is

Blougly reads a source/ directory and writes a static site to an output directory. Markdown files with YAML front matter become pages, Blade templates lay them out, and assets are copied verbatim. The output is plain HTML: no PHP runtime, no database, no build-time asset pipeline. If you can serve a folder, you can serve a Blougly site.

It was built to practice Ports and Adapters. The architecture is the point, and the generator is what came out of practicing it. If you are looking for a feature-rich SSG, this is not one. If you are looking for a small codebase where every dependency is an interface and the domain imports nothing, you will like reading it.

Install

git clone https://github.com/felipeverse/blougly
cd blougly
composer install

Docker is an alternative if you would rather not install PHP locally:

git clone https://github.com/felipeverse/blougly
cd blougly
docker compose run --rm blougly

Usage

From a clone, as a contributor:

php bin/console.php

Installed as a dependency, as a site owner:

vendor/bin/console.php

Both accept the same options:

Option Default Description
--source ./source Source directory to read
--output ./public Output directory to write

Both --source=x and --source x are accepted. Defaults resolve against the current working directory. The output directory is deleted and recreated on every build, so never point --output at a directory you care about. A missing source directory is reported as an error and exits with status 1.

Source types

Everything Blougly reads lives under the source directory. A source directory with no assets/, no data/ and no contents/ is perfectly valid, it just builds an empty site.

Path Accepts Output Notes
assets/ any file assets/ Copied verbatim. Dotfiles are skipped.
data/ .json data/ Any other extension throws a RuntimeException. Exposed to templates as $data.
contents/ .md HTML Front matter plus Markdown body. Any other extension throws a RuntimeException. Exposed to templates as $contents.
site/ .blade.php .html One page per file, extension swapped. Any other extension throws a RuntimeException.
views/ Blade templates n/a Rendered, not read as pages.
config.json JSON n/a Optional. A missing file means an empty site config. Exposed to templates as $site.

Two rules hold across all readers: dotfiles are ignored, and a file with the wrong extension fails the build with a RuntimeException naming the file.

Front matter keys are yours to choose. The demo site uses title, published, tags, template and draft, and each key becomes a template variable. draft: true excludes the page from the build. Omitting template outputs the Markdown body as-is.

Architecture

flowchart LR
    CLI["bin/console.php<br/>BuildCommand"] -->|implements| SI["Ports/Inbound<br/>SiteBuilder"]
    SI --> APP["Application<br/>BuildSite · LoadSources · PageRenderer"]
    APP --> DOM["Domain<br/>Pages · ValueObjects · Collections"]
    APP -->|implements| SO["Ports/Outbound<br/>12 interfaces"]
    SO --> AD["Adapters/Outbound<br/>FileSystem · Json · Markdown · Blade"]
    CR["Bootstrap/Container<br/>composition root"] -.wires.-> CLI
    CR -.wires.-> SO
Loading

Domain imports nothing. It holds pages, value objects and collections, and it has no idea whether pages come from Markdown, JSON or Blade. Application orchestrates: LoadSources fans out across the six source readers, BuildSite sequences the build, PageRenderer decides which template each page gets. Ports are the contracts, twelve interfaces on the outbound side and one on the inbound side. Adapters are the swappable implementations, with Blade, CommonMark and the local filesystem as the concrete choices. Bootstrap/Container is the only place that knows which implementation backs which interface.

The --source and --output options are composition config, not build input. SiteBuilder::build() takes no arguments, and BuildPaths normalizes both directories to canonical absolute paths so that consumers constructing the container programmatically get the same guarantees as the CLI.

Development

make build         # build the site inside the container
make serve         # serve the site at http://localhost:8080 (PORT= to change it)
make clean         # remove the generated output
make help          # list every target

Without Docker:

php bin/console.php
vendor/bin/pest    # test suite

License

MIT. See LICENSE.

About

Blougly: an ugly static site generator that gets out of your way

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages