SiteBuilder
SiteBuilder is a flexible in-memory static site generator built in TypeScript. Unlike traditional static site generators that output files to disk, SiteBuilder keeps everything in memory and relies on plugins to deploy or output your site.
How It Works
- Load — Reads data files (YAML/JSON), includes (layouts/partials), public assets, and site content (Markdown/HTML)
- Process — Parses frontmatter, validates schemas, builds collections from tags, and renders templates
- Build — Applies layouts, generates permalinks, and caches pages by content hash
- Deploy — Plugins handle output (e.g., the
ngrokplugin deploys via Traffic Policy)
Content Pipeline
src/data/*.yaml → Global data (accessible as `data.filename`)
src/includes/*.eta → Layouts & partials (with optional frontmatter)
src/public/* → Static assets (CSS, JS, images)
src/site/*.md → Pages (Markdown with frontmatter)
Pages are processed through:
- Frontmatter parsing — YAML metadata (title, date, tags, permalink, layout, draft)
- Template rendering — Eta templating with access to
data,collections, andincludes - Markdown conversion — Via markdown-it
- Layout wrapping — Content injected into layout templates
Frontmatter Options
---
title: My Page # Page title
date: 2024-01-15 # Publication date
draft: true # Exclude from build (unless BUILD_DRAFTS=true)
tags: [blog, tutorial] # Add to collections
permalink: /custom-url/ # Custom URL path
alias: /old-url/ # Redirect alias
layout: post # Layout template name
---
Features
- In-Memory Build — No disk I/O during build; plugins decide output strategy
- Plugin Hooks —
beforeBuild,afterBuild,beforeRenderContent,afterRenderLayout, and more - Collections — Auto-generated from tags, accessible in templates
- Caching — Content-hash based caching skips unchanged pages
- Concurrent Processing — Configurable parallelism for large sites
Installation
Prerequisites
Install
git clone https://github.com/nijikokun/SiteBuilder.git .
bun install
Building
bun run build
Deploying with ngrok plugin
The ngrok plugin deploys your site using Traffic Policy and Cloud Endpoints. Content is served via the custom-response action.
CEL Expressions
You can use CEL expressions in your content with ${...} syntax (e.g., ${req.headers['x-custom']}). To output a literal ${ without it being interpreted as a CEL expression, escape it as \${.
Requirements
To use the ngrok deploy plugin you will need:
Once you have these you should set the following environment variables:
export NGROK_API_KEY=<your-api-key>
export NGROK_ENDPOINT_URL=https://<your-reserve-domain>
Then run:
bun run build
Auto-Deploy with GitHub Actions
To automatically deploy on push to main, set up a GitHub Environment with your secrets:
- Go to Settings → Environments → New environment
- Name it (e.g.,
productionor your domain) - Add secrets:
NGROK_API_KEY— Your ngrok API keyNGROK_ENDPOINT_URL— Your endpoint URL (e.g.,https://example.ngrok.app)
The included workflow at .github/workflows/deploy.yml handles the rest:
name: build
on:
push:
branches:
- main
jobs:
build:
environment: production # Change to your environment name
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- env:
NGROK_API_KEY: ${{ secrets.NGROK_API_KEY }}
NGROK_ENDPOINT_URL: ${{ secrets.NGROK_ENDPOINT_URL }}
run: bun run build
Directory Structure
/
├── src/
│ ├── data/
│ │ └── site.yaml
│ ├── includes/
│ │ └── layout.eta
│ └── site/
│ ├── index.md
├── lib/
│ └── SiteBuilder.ts
├── plugins/
│ └── ngrok.ts
└── config.ts
└── index.ts
src/- The source directory for your site content.data/- Contains global data files (YAML, JSON) accessible in your templates.includes/- Contains layouts and partials used in templates.public/- Contains public assets files.site/- Contains the main site content (Markdown, HTML, etc.).
lib/- Source code for SiteBuilder lives here.SiteBuilder.ts
plugins/- Site builder plugins directoryngrok.ts- Plugin to deploy site to the ngrok platform.
config.ts- Builder and plugin configuration goes here.index.ts- Entry point for building, add plugins here.
Plugins
SiteBuilder supports a plugin system that allows developers to extend its core functionality. Plugins can hook into the build process at different stages such as beforeBuild, afterBuild, and more.
Available Plugins
ngrok- Deploy site to ngrok via Traffic Policy and Cloud EndpointsMinifyCssPlugin- Minifies CSS files from thesrc/publicdirectory
Creating your own Plugin
- Create a typescript file under the
plugins/directory.touch ./plugins/MyPlugin.ts - Implement the Plugin Interface.
import { Page, SiteBuilder } from '../lib/SiteBuilder'; class MyPlugin { version: string; constructor() { this.version = '1.0.0'; } afterBuild(pages: Page[], builder: SiteBuilder): void { console.log('Built Pages:'); pages.forEach(page => { console.log(`- ${page.filePath}`); }); } } export default MyPlugin; - Add it to the entry point.
import { MyPlugin } from './plugins/MyPlugin.ts' // ... builder.use(new MyPlugin()); - Run
bun run build
Plugin Interface
Plugins should implement the following structure:
interface Plugin {
version: string; // Version of the plugin
initialize?(builder: SiteBuilder): void | Promise<void>;
beforeBuild?(builder: SiteBuilder): void | Promise<void>;
afterBuild?(pages: Page[], builder: SiteBuilder): void | Promise<void>;
// Additional hooks can be defined as needed
}
Activity
License
The code in this repository, including the index.ts, config.ts files, and the lib/ and plugins/ directories, is licensed under the MIT License.