A modular static site generator library for Rust.
librawssg is a collection of crates that together form a flexible and extensible framework for building static site generators. The project is designed with modularity, testability, and safety in mind, leveraging Rust's type system and trait abstractions.
- Modular architecture – Each aspect (configuration, filesystem, content processing, templating, compilation) is isolated into its own crate.
- Pluggable processors – Define custom content processors via the
Processortrait. - Template engine integration – Built-in support for Tera templates through the
TeraRenderer(optional, enabled by default). - Strong filesystem abstraction – Trait-based filesystem with built-in path traversal protection.
- Atomic output generation – The build pipeline writes to a temporary directory and atomically replaces the final output.
- Comprehensive configuration – YAML/JSON support, validation, and nested site/build settings.
- Extensible – Add custom renderers, context builders, and post-processing generators.
- Strict linting – Deny-level lints for clippy and rustc ensure high code quality.
- Demo application – A complete example showing how to assemble the parts into a working static site.
The workspace consists of the following crates:
| Crate | Description |
|---|---|
librawssg |
Facade crate that re-exports all other crates for convenience. |
librawssg_config |
Configuration data structures and validation. |
librawssg_fs |
Filesystem abstraction trait and real implementation. |
librawssg_handler |
Core document, metadata, and processor contracts. |
librawssg_templates |
Rendering traits and Tera implementation. |
librawssg_compiler |
Build pipeline orchestration. |
librawssg_error |
Unified error types and result alias. |
librawssg_demo |
Example application demonstrating usage of the framework. |
- Rust toolchain (stable, edition 2024) – install via rustup
- Cargo (comes with Rust)
Clone the repository and build all crates:
git clone https://github.com/mroczect/librawssg.git
cd librawssg
cargo buildThe librawssg_demo crate provides a working example. To run it:
cargo run -p librawssg_demoThis will process .raw HTML fragment files from librawssg_demo/src/content, render them using a Tera template, copy static assets, and output the site into librawssg_demo/dist.
Add librawssg to your Cargo.toml:
[dependencies]
librawssg = "1.0.0"Then you can import the necessary components. Here is a minimal example that sets up a pipeline:
use librawssg::{
Config, ContentRule, Document, FileSystem, Metadata, PipelineBuilder, Processor,
RealFs, RenderContext, Renderer, TeraContextBuilder, TeraRenderer,
};
use std::path::{Path, PathBuf};
// Implement a custom processor for .txt files
struct TextProcessor;
impl Processor for TextProcessor {
fn name(&self) -> &'static str { "text" }
fn can_process(&self, rel: &Path, _orig: &Path) -> bool {
rel.extension().and_then(|e| e.to_str()) == Some("txt")
}
fn process(
&self,
fs: &dyn FileSystem,
rel: &Path,
content_dir: &Path,
) -> librawssg::Result<Option<Document>> {
let body = fs.read_to_string(&content_dir.join(rel))?;
let meta = Metadata::new("Page", "Description")?;
let url = rel.with_extension("html").to_string_lossy().to_string();
let doc = Document::new(
meta,
body,
url.clone(),
PathBuf::from(&url),
rel.to_path_buf(),
0,
"page".to_string(),
false,
)?;
Ok(Some(doc))
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut config = Config::new().with_site_name("My Site");
config.add_content_rule(ContentRule::new("page", "**/*.txt", "base.tera"));
config.build.content_dir = "content".into();
config.build.output_dir = "dist".into();
config.build.static_dir = "static".into();
let mut renderer = TeraRenderer::new();
renderer.load_templates_dir(Path::new("templates"))?;
let pipeline = PipelineBuilder::new()
.config(config)
.content_dir("content")
.output_dir("dist")
.with_fs(Box::new(RealFs))
.with_renderer(Box::new(renderer))
.with_context_builder(Box::new(TeraContextBuilder))
.add_processor(Box::new(TextProcessor))
.build()?;
pipeline.run()?;
println!("Site generated!");
Ok(())
}For a more detailed example, see the librawssg_demo source code.
The Config struct holds all settings required for the build. It includes:
site: Site-wide metadata (name, description, navigation, etc.)build: Paths for content, output, templates, and static assets.content_rules: A list ofContentRuleobjects that map file patterns to templates.extra: Arbitrary key-value data.
Configuration can be loaded from YAML or JSON using Config::from_yaml_str / Config::from_json_str.
Content files are processed by implementations of the Processor trait. Each processor declares which files it can handle via can_process(), and then transforms them into Document objects. The pipeline walks the content directory, determines the appropriate processor for each file, and collects the resulting documents.
The Renderer trait abstracts template rendering. The built-in TeraRenderer uses the Tera template engine. A ContextBuilder creates the render context for each document; the default TeraContextBuilder populates it with page and site data.
The PipelineBuilder assembles all components (filesystem, renderer, processors, context builder, generators) and produces a Pipeline. Calling pipeline.run() performs the following steps:
- Processes all content files.
- Renders non-list documents.
- Optionally generates list pages (index pages) for content types with list support enabled.
- Copies static assets.
- Executes any custom generators.
- Atomically replaces the output directory.
You can extend the framework by implementing the following traits:
Processor– For handling new file types or custom transformations.RendererandRenderContext– To integrate a different template engine.ContextBuilder– To customize the data passed to templates.Generator– To add extra outputs like RSS feeds, sitemaps, or search indexes.
All components are passed to the pipeline as boxed trait objects, so they are easily swappable.
The workspace enforces strict linting via [workspace.lints] in the root Cargo.toml. Many clippy and rustc lints are set to deny, including unsafe_code = "forbid", unwrap_used = "deny", expect_used = "deny", panic = "deny", and many others. This ensures high code quality and safety. When contributing, please ensure your code passes cargo clippy --all --all-targets --all-features -- -D warnings and cargo fmt --check.
cargo test --workspacecargo fmt --allContributions are welcome! Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md for guidelines. By participating, you agree to abide by the project's code of conduct.
This project is licensed under the MIT License. See the LICENSE file for details.
This project uses the following open-source crates (among others):