Skip to content

kamoshi/hauchiwa

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

185 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hauchiwa

Crates.io Docs.rs

A flexible, incremental, graph-based static site generator library for Rust. It provides the building blocks to create your own custom static site generator tailored exactly to your needs.

Unlike traditional SSGs that force a specific directory structure or build pipeline, Hauchiwa gives you a task graph. You define the inputs (files, data), the transformations (markdown parsing, image optimization, SCSS compilation), and the dependencies between them. Hauchiwa handles the parallel execution, caching, and incremental rebuilds.

If you are tired of:

  • Rigid frameworks that force their file structure on you (Jekyll, Hugo).
  • Complex config files that are hard to debug.
  • Bloated JavaScript bundles for simple static content.

Then Hauchiwa is for you.

Quick Start

Add hauchiwa to your Cargo.toml:

[dependencies]
# Check crates.io for the latest version
hauchiwa = "*"
# Serde is needed to parse frontmatter
serde = { version = "1", features = ["derive"] }

Create your generator in src/main.rs:

use hauchiwa::{Blueprint, Website, Output};
use serde::Deserialize;


// 1. Define your content structure (Frontmatter)
#[derive(Deserialize, Clone)]
struct Post {
    title: String,
}

fn main() -> anyhow::Result<()> {
    // 2. Create the configuration
    // We explicitly specify the global data type as `()`
    // since we don't have any global state yet.
    let mut config = Blueprint::<()>::new();

    // 3. Add a loader to glob markdown files
    // `posts` is `Many<Document<Post>>`
    let posts = config.load_documents::<Post>()
        .source("content/**/*.md")
        .register()?;
    
    let css = config.load_css()
        .entry("styles/**/*.scss")
        .register()?;

    // 4. Define a task to render pages
    // We declare that this task depends on `posts`.
    config
        .task()
        .each(posts)
        .using(css)
        // Iterate over loaded posts
        .map(|_, post, css| {
            // retrieve css bundle
            let css = css.get("styles/main.scss")?;
            
            // format html
            let html_content = format!("<h1>{}</h1>", post.matter.title);
            
            // create a page structure
            // Output::html creates pretty URLs (e.g., /foo/index.html)
            Ok(Output::html(&post.meta.path, html_content))
        });

    // 5. Build the website
    let mut website = config.finish();
    website.build(())?;

    Ok(())
}

Key Features

  • Graph-based: Define your build as a graph where tasks are wired together using strictly typed handles rather than rigid file paths. This structure automatically resolves complex dependencies, ensuring shared ancestor tasks execute exactly once before efficiently distributing their results.
  • Incremental: The engine identifies the specific task responsible for a changed file and marks only its dependent subgraph as "dirty". By re-executing only this precise chain of tasks, the system avoids wasteful full rebuilds and delivers near-instant updates.
  • Parallel: A threaded execution engine schedules tasks to run on a thread pool the moment their dependencies are resolved. This saturates your CPU cores automatically, processing heavy assets and content concurrently without manual async orchestration.
  • Type-safe: Dependencies are passed as generic tokens, allowing the Rust compiler to enforce that the output type perfectly matches the input type.
  • Asset pipeline: Built-in support for:
    • Images: Automatically generates multi-format sources (WebP, AVIF) via the image crate.
    • CSS/Sass: Integrates grass to compile and minify stylesheets, outputting CSS bundles.
    • JavaScript: Bundling and minification via esbuild.
    • Svelte: Orchestrates Deno to compile components into separate SSR and hydration scripts, automatically propagating import maps for seamless client-side interactivity.
    • Search: Static search indexing via pagefind.
    • Sitemap: Sitemap generation via sitemap-rs.

Core Concepts

  • Blueprint: The blueprint of your site. You use this to register tasks and loaders.
  • Task: A single unit of work. Tasks can depend on other tasks.
    • Coarse-grained: Tasks that produce a single output.
    • Fine-grained: Tasks that produce multiple outputs.
  • Handle: A reference to the future result of a task. You pass these to other tasks to define dependencies.
    • One: A handle to a single (coarse-grained) output.
    • Many: A handle to multiple (fine-grained) outputs.
  • Loader: A kind of a task that reads data from the filesystem (e.g., markdown files, images).
  • Website: The engine that converts the graph defined in Blueprint into a proper static website.

Documentation

Introduction is available in the docs/ directory (run make watch), or you can visit the online version. The best place to learn the API is the full documentation. It covers the available features in depth.

Examples

Some examples are available in the examples/ directory.

In addition, there are also some real-world examples:

Feature flags

By default, Hauchiwa is built with the following features, but you can opt out of them by disabling them in your Cargo.toml file, if you don't need them.

  • grass: Enables SCSS/Sass compilation.
  • image: Enables image optimization (WebP, resizing).
  • tokio: Enables the Tokio runtime for async tasks.
  • live: Enables live-reload during development.
  • server: Enables the built-in development server.
  • pagefind: Enables static search indexing.
  • sitemap: Enables sitemap.xml generation.

License

GPL-2.0 or later.

About

Flexible static site generator library with incremental rebuilds and cached image optimization

Topics

Resources

License

Stars

Watchers

Forks