Skip to content

Repository files navigation

Zest

Zest SSG

Zealous Efficient Static Toolkit

License · Quick Start · Docs


Zest is a hybrid F# + C# static site generator where templates are real code — not strings. Built on the philosophy that your templating language and your host language should be one and the same.

Features

  • Template as Code.zest.fsx are real F# scripts executed at build time via dotnet fsi. Full F#: list comprehensions, pattern matching, string interpolation, arbitrary computation.
  • .zhtml Lightweight Pages — Pure HTML pages with optional Nunjucks template syntax. No FSI overhead.
  • HTML DSL — Compose HTML declaratively: render [ h1 []; p [] ].
  • Inline Markdown — Write Markdown directly inside a .zest.fsx page with the md helper and mix it with the HTML DSL: md """# Title\n**bold**""".
  • Markdown — Standard .md files with frontmatter support.
  • ZCSS — A CSS superset with nesting, F#-style let bindings, math expressions, color functions, and mixins — compiled to standard CSS.
  • 11ty-Compatible Templates — Full Nunjucks (.njk), Liquid (.liquid), Handlebars (.hbs), Mustache (.mustache), HAML (.haml), Pug (.pug), and WebC (.webc) support — all with auto-conversion to Nunjucks engine for filters, macros, template inheritance, and Zest API integration.
  • _init.fsx — Optional initialization script (runs before build) to inject dynamic data, load JSON/TOML, read env vars.
  • TOML Config — Zero-config defaults; customize via _config.toml and _data/*.toml. No YAML.
  • Live Reloadzest serve watches for changes and auto-rebuilds.
  • Batch Evaluation — Multiple F# page scripts evaluated in a single FSI process for fast builds.
  • Incremental Builds — File change detection skips unchanged pages and assets.
  • Cross-Platform — Builds for Windows x64, Linux x64/ARM64, macOS ARM64.

Quick Start

# Scaffold a new project
zest init my-site

# Develop with live reload
cd my-site && zest serve --port 8080

# Build for production
zest build

# Preview the built site
zest preview

Example: .zest.fsx Page

// @title Hello World
// @layout default
// @description My first Zest page

let pageTitle = "Hello from F#"
let items = ["F#"; "Zest"; "SSG"]

render [
    h1 [ text pageTitle ]
    p  [ text "This page is generated by real F# code at build time." ]
    ul [ for i in items -> li [ text i ] ]
]

Example: Inline Markdown in .zest.fsx

The md helper renders a Markdown string to an HTML string, so you can blend prose with the F# HTML DSL in the same page — md returns a plain string, just like every other DSL builder:

// @title About
// @layout default

open Zest.Dsl

render [
    divC "about" [
        md """
# About

This page is a **native template** written in `.zest.fsx` (real F#), where
Markdown and the HTML DSL live side by side.

Learn more at the [Zest repository](https://github.com/zest-ssg/zest).
"""
    ]
]

Example: ZCSS Stylesheet

// F#-style let bindings with math expressions
let primary    = #3b82f6
let space1     = 0.25r
let space4     = space1 * 4     // 1rem
let primary-light = primary |> lighten(45%)

// Two-letter property shorthands
.tag
  color: $primary
  background-color: $primary-light
  padding-block: $space4
  border-radius: 9999px

Compiles to:

.tag {
  color: #3b82f6;
  background-color: #adf4ff;
  padding-block: 1rem;
  border-radius: 9999px;
}

Example: _init.fsx

// _init.fsx — runs before every build
addGlobal "api_url" "https://api.example.com"

let team = loadJson "data/team.json"
addGlobal "team" team

let env = loadEnv "ZEST_ENV"
if env = "production" then
    addGlobal "analytics_id" "UA-XXXXX-Y"

Project Structure

my-site/
├── _config.toml            # Site configuration (TOML)
├── _init.zest.fsx         # Optional init script (runs before build)
├── _data/
│   └── site.toml           # Global data (accessible from scripts/templates)
├── content/
│   ├── index.zest.fsx     # Home page (F# script template)
│   ├── about.md            # About page (Markdown)
│   └── posts/
│       ├── hello-world.zest.fsx
│       └── contact.zhtml   # Pure HTML (no FSI overhead)
├── _layouts/
│   ├── default.html        # Layouts (Nunjucks or native replace)
│   └── post.html
├── assets/
│   └── css/
│       └── style.zcss      # ZCSS → auto-compiled to style.css
└── _site/                  # Build output (auto-generated)

Architecture

Project Language Responsibility
Zest.App C# CLI entry point, command routing
Zest.Engine F# Core engine: builds, HTML DSL, ScriptRunner, Markdown, ZCSS compiler, Nunjucks template engine, 11ty-compatible language layer
Zest.Dsl F# Precompiled DSL helpers for FSI script evaluation
Zest.Infra C# Configuration loading, file watching, dev server

Build from Source

git clone https://github.com/zest-ssg/zest
cd zest
dotnet build Zest.sln

# Publish for your platform
dotnet publish src/Zest.App/Zest.App.csproj -c Release -r win-x64 --self-contained false
# Linux:  -r linux-x64
# macOS:  -r osx-arm64

Documentation

File Types

Extension Purpose Processing
.zest.fsx F# script templates (F# + Markdown + HTML DSL) Compiled via dotnet fsi
.njk Nunjucks templates (filters, macros, inheritance, Zest API) Rendered via NunjucksEngine
.liquid Liquid templates (Jinja2 family, auto-converted) Converted → NunjucksEngine
.hbs Handlebars templates (auto-converted to Nunjucks) HandlebarsMustacheConverter → NunjucksEngine
.mustache Mustache templates (auto-converted to Nunjucks) HandlebarsMustacheConverter → NunjucksEngine
.webc WebC components (SSR preprocessed) WebC preprocessor → NunjucksEngine
.haml HAML templates (auto-converted to HTML → Nunjucks) HamlConverter → NunjucksEngine
.pug Pug templates (auto-converted to HTML → Nunjucks) PugConverter → NunjucksEngine
.zcss ZCSS stylesheets (CSS superset) Compiled to .css
.md Standard Markdown Rendered to HTML
.toml Configuration and data (no YAML) Parsed at build time

Commands

Command Description
zest build Build the site to _site/
zest serve Start dev server with live reload
zest preview Preview the built site
zest init <name> Scaffold a new project
zest clean Clean build output

ZCSS Reference

Feature Syntax
Variables (SCSS) $name: value;
Variables (F#) let name = value
Math let x = 0.25r * 4
Color functions lighten(#hex, %), darken(#hex, %), mix(a, b, %)
Pipe operator value |> fn(args)fn(value, args)
Unit shorthands rrem, p%
Property shorthands pypadding-block, mxmargin-inline, bgcbackground-color
Nesting Indent or brace mode
Mixins @mixin, @include
Loops @each, @for
Conditionals @if, @else
Built-in modules @use "zest:utilities", @use "zest:palette", etc.

Layout Engines

Engine Config Value Features
Nunjucks (default) template_engine = "nunjucks" Filters, expressions, {% if %}, {% for %}, macros, template inheritance, Zest API filters (pages_by_tag, recent, by_collection, search, where) — also handles .liquid, .hbs, .mustache, .webc, .haml, .pug via auto-conversion
Native Replace template_engine = "replace" Simple {{ variable }} substitution

HTML DSL Reference

// Elements
h1 [ text "Title" ]
p  [ text "Paragraph" ]
a  [ href "https://example.com"; text "Link" ]

// Attributes
div [ class' "container"; id "main" ] [ ... ]

// CSS class shortcuts
divC "card" [ p [ text "Content" ] ]   // <div class="card">
spanC "badge" [ text "New" ]           // <span class="badge">

// List comprehensions
ul [ for item in items -> li [ text item ] ]

// Conditionals
if condition then
    p [ text "Yes" ]
else
    p [ text "No" ]

_init.fsx API

Function Purpose
addGlobal key value Inject key-value into global data
loadJson path Parse JSON file
loadToml path Parse TOML file
loadEnv key Read environment variable
console_log msg Debug output to stderr
exec cmd args Run shell command

Design Philosophy

Zest is not a general-purpose static site generator. It is a specific answer to specific constraints.

  1. F# as the Template — The template is the program. .zest.fsx files are real F# code, not strings.
  2. ZCSS as the Layout Engine — Not a CSS pre-processor, but a layout engine that emits CSS.
  3. TOML as the Contract — No YAML. Ever.
  4. JavaScript as Order — No Node.js, no npm, no bundlers. JavaScript exists only for client-side interactivity.
  5. The Zealous Few — Built for those who love F#, hate YAML, and prefer simple tools.

Acknowledgements

Zest would not have been possible without the help of my capable AI assistants, who supported me through design, debugging, and documentation:

  • Claude — architecture and design review
  • GLM — research and experimentation
  • DeepSeek — debugging and performance tuning
  • Hunyuan — implementation and documentation support

Thank you all for helping bring this project to life.

License

Apache 2.0 — see LICENSE.

About

F#-powered static site generator with template-as-code & ZCSS styles (no YAML, no Node.js)

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages