index.md

# bok

bok is a fast, minimal static site generator built with Bun. It converts Markdown files to HTML using TypeScript template literals, with a focus on documentation sites and books.

# Features

  • Fast - Built on Bun for quick builds and hot reloading
  • Simple - Markdown in, HTML out, minimal configuration
  • Flexible Templates - Use TypeScript template literals for layouts
  • Live Reload - Auto-refresh browser on file changes
  • Book Theme - Built-in theme inspired by mdBook/GitBook
  • Table of Contents - Define page order with a simple TOC file
  • Right-side Navigation - Auto-generated on-page heading navigation
  • Front Matter - Add metadata to pages with simple key-value pairs

# Quick Start

# Install bun if you haven't already
curl -fsSL https://bun.sh/install | bash

# Clone and install
git clone https://github.com/alajmo/bok
cd bok
bun install

# Create a new site
bun run mod.ts init

# Start development server
bun run mod.ts serve config.ts

# How It Works

  1. Configuration - Define your site in config.ts
  2. Content - Write pages in Markdown in the content/ directory
  3. TOC - Define page order in content/toc.md
  4. Build - Run bok build to generate static HTML
  5. Serve - Run bok serve for development with live reload

# Philosophy

In the beginning, all you want is results. In the end, all you want is control.

bok aims to be:

  • Explicit over implicit - No magic, clear configuration
  • Minimal core - Do one thing well: Markdown to HTML
  • Extensible - Hooks and custom layouts for advanced use cases

getting-started.md

# Getting Started

This guide will help you create your first bok site.

# Prerequisites

You need Bun installed:

curl -fsSL https://bun.sh/install | bash

# Installation

# From Source

git clone https://github.com/alajmo/bok
cd bok
bun install

# Global Install

After cloning, you can install bok globally:

make install

This creates a bok command you can run from anywhere.

# Create a New Site

# Interactive Mode

Run the init command and follow the prompts:

bok init

You'll be asked to:

  1. Choose extend (use existing theme) or create (copy theme files)
  2. Select a theme: basic or book

# Non-Interactive Mode

# Extend the book theme
bok init --mode extend --theme book

# Project Structure

After initialization, your project looks like this:

my-site/
├── config.ts        # Site configuration
└── content/
    ├── toc.md       # Table of contents (page order)
    ├── index.md     # Home page
    └── ...          # Your markdown pages

# Development Workflow

# Start the Dev Server

bok serve config.ts

This will:

  • Build your site to the output directory
  • Start a local server at http://localhost:5000
  • Watch for file changes and rebuild automatically
  • Reload your browser when files change

# Build for Production

bok build config.ts

The generated site will be in the site/ directory (or whatever you configured as paths.output).

# Adding Pages

  1. Create a new .md file in content/:
# My New Page

This is my new page content.
  1. Add it to content/toc.md:
- [My New Page](my-new-page.md)
  1. Save and watch the browser reload with your new page.

# Next Steps

  • Learn about CLI Commands
  • Understand Configuration
  • Explore the Book Theme

usage.md

# CLI Commands

bok provides a simple command-line interface for building and serving your site.

# Usage

bok <command> [config]

All commands except init accept an optional path to your config file. If not provided, it defaults to config.ts in the current directory.

# Available Commands

Command Description
init Initialize a new site
build Build static HTML files
watch Build and rebuild on file changes
serve Build, serve, and live reload
clean Remove the output directory

# Global Options

bok --help     # Show help
bok --version  # Show version

# Examples

# Initialize a new site
bok init

# Build using default config.ts
bok build

# Build with explicit config path
bok build ./my-site/config.ts

# Start development server
bok serve config.ts

# Start server with custom port
bok serve --port 3000 config.ts

init.md

# init

Initialize a new bok site in the current directory.

# Usage

bok init [options]

# Options

Option Description
--mode <string> Create mode: extend or create
--theme <string> Theme to use: basic, book, or path
--theme-path <string> Path to custom theme config (when theme is path)

# Modes

# Extend Mode (Recommended)

Extends an existing theme. Creates a minimal config.ts and copies the theme's content directory.

bok init --mode extend --theme book

This creates:

  • config.ts - References the theme, lets you override params
  • content/ - Copy of the theme's example content

Your config will look like:

export default {
  extends: "book",
  params: {
    title: "My Site",
  },
};

# Create Mode

Copies all theme files into your project for full customization.

bok init --mode create --theme book

This creates:

  • config.ts - Full configuration
  • content/ - Content directory
  • layout/ - Template files
  • assets/ - CSS, JS, images

# Interactive Mode

Run without options to use interactive prompts:

bok init

You'll be asked:

  1. Mode: Extend or create from scratch?
  2. Theme: Which theme to use?

# Using a Custom Theme

Point to your own theme config:

bok init --mode extend --theme path --theme-path /path/to/theme/config.ts

# Examples

# Interactive mode
bok init

# Quick start with book theme
bok init --mode extend --theme book

# Full theme customization
bok init --mode create --theme basic

build.md

# build

Build your site into static HTML files.

# Usage

bok build [config]

# Arguments

Argument Description Default
config Path to config file config.ts

# What It Does

  1. Cleans the output directory
  2. Discovers pages based on your file discovery mode (walk, glob, or toc)
  3. Processes each page:
    • Extracts front matter
    • Converts Markdown to HTML
    • Generates right-side table of contents
    • Applies the layout template
  4. Copies assets (theme assets + public directories)
  5. Outputs a summary table

# Output

After building, you'll see a summary:

[INFO] Building
┌─────────┬────┐
│         │ EN │
├─────────┼────┤
│ # Pages │ 12 │
└─────────┴────┘

# Output Directory

By default, files are output to site/ relative to your config file. Configure this with paths.output:

export default {
  paths: {
    output: "dist",  // Output to dist/ instead
  },
};

# URL Structure

# Pretty URLs (default)

content/getting-started.md  →  site/getting-started/index.html
content/guide/intro.md      →  site/guide/intro/index.html
content/index.md            →  site/index.html

# Ugly URLs

Set uglyURLs: true in your config:

content/getting-started.md  →  site/getting-started.html
content/guide/intro.md      →  site/guide/intro.html

# Examples

# Build with default config
bok build

# Build with explicit config
bok build ./docs/config.ts

# Build and then deploy
bok build config.ts && rsync -av site/ server:/var/www/

watch.md

# watch

Build your site and automatically rebuild when files change.

# Usage

bok watch [config]

# Arguments

Argument Description Default
config Path to config file config.ts

# What It Does

  1. Performs an initial build
  2. Watches these directories for changes:
    • content/ - Your markdown files
    • assets/ - Theme assets
    • layout/ - Template files
  3. Rebuilds when any file changes

# Debouncing

Changes are debounced with a 500ms interval to prevent multiple rapid rebuilds when saving multiple files.

# Differences from serve

Feature watch serve
Builds on change Yes Yes
HTTP server No Yes
Live reload No Yes

Use watch when you:

  • Have your own HTTP server
  • Just want to rebuild files
  • Are building for deployment

Use serve when you:

  • Want a complete development environment
  • Need live reload in browser

# Examples

# Watch with default config
bok watch

# Watch specific config
bok watch ./docs/config.ts

serve.md

# serve

Build, serve, and live reload your site during development.

# Usage

bok serve [options] [config]

# Arguments

Argument Description Default
config Path to config file config.ts

# Options

Option Description Default
--port <port> HTTP server port 5000
--ws-port <port> WebSocket port for live reload 5001
--reload Enable live reload true

# What It Does

  1. Performs an initial build
  2. Starts an HTTP server to serve your site
  3. Starts a WebSocket server for live reload
  4. Watches for file changes and rebuilds
  5. Notifies the browser to reload after rebuilds

# Live Reload

When --reload is enabled (default), bok:

  1. Injects a small JavaScript snippet into HTML pages
  2. Opens a WebSocket connection to the dev server
  3. Listens for build completion events
  4. Automatically reloads the page when content changes

# Server Details

The HTTP server:

  • Serves static files from the output directory
  • Returns index.html for directory requests
  • Serves 404/index.html for missing pages (if it exists)
  • Logs all requests to the console

# Examples

# Start with defaults (port 5000)
bok serve config.ts

# Custom HTTP port
bok serve --port 3000 config.ts

# Custom WebSocket port
bok serve --ws-port 3001 config.ts

# Disable live reload
bok serve --reload=false config.ts

# Configuration

You can also set serve options in your config file:

export default {
  serve: {
    reload: true,
    port: 5000,
    wsPort: 5001,
  },
};

Command-line options override config file settings.


clean.md

# clean

Remove the output directory.

# Usage

bok clean [config]

# Arguments

Argument Description Default
config Path to config file config.ts

# What It Does

Deletes the entire output directory (default: site/).

This is useful for:

  • Cleaning up before a fresh build
  • Removing stale files from deleted pages
  • Resetting your project state

# Note

The build command already cleans the output directory before building, so you typically don't need to run clean manually.

# Examples

# Clean with default config
bok clean

# Clean specific project
bok clean ./docs/config.ts

configuration.md

# Configuration

bok uses a TypeScript configuration file (config.ts) to define your site settings.

# Basic Config

export default {
  extends: "book",

  paths: {
    output: "site",
  },

  params: {
    title: "My Documentation",
    author: "Your Name",
  },
};

# Configuration Options

# extends

Extend a built-in or custom theme.

extends: "book"        // Built-in theme
extends: "basic"       // Built-in theme
extends: "/path/to/theme/config.ts"  // Custom theme

# rootUrl

Base URL prefix for all links. Useful when deploying to a subdirectory.

rootUrl: "/docs"  // Site served at example.com/docs/
rootUrl: ""       // Site served at root (default)

# uglyURLs

Use .html extensions instead of directory-based URLs.

uglyURLs: false  // /about/ (default)
uglyURLs: true   // /about.html

# paths

Configure directory locations.

paths: {
  content: "content",     // Markdown files location
  output: "site",         // Build output directory
  assets: "assets",       // Theme assets (CSS, JS, images)
  layout: "layout",       // Template files
  defaultLayout: "index.ts",  // Default page template
  public: ["public"],     // Additional directories to copy
}

All paths are relative to the config file location.

# files

Configure how pages are discovered.

// Table of contents mode (recommended for books)
files: {
  type: "toc",
  file: "toc.md",
}

// Walk all markdown files
files: {
  type: "walk",
}

// Glob pattern
files: {
  type: "glob",
  glob: "**/*.md",
}

# serve

Development server settings.

serve: {
  reload: true,   // Enable live reload
  port: 5000,     // HTTP server port
  wsPort: 5001,   // WebSocket port
}

# hooks

Lifecycle hooks for custom processing.

hooks: {
  async beforeSite(site, pages, opts) {
    // Called before building any pages
  },
  async afterSite(site, pages, opts) {
    // Called after all pages are built
  },
  async beforePage(site, page, index, pages, opts) {
    // Called before each page is processed
  },
  async afterPage(site, page, index, pages, opts) {
    // Called after each page is processed
  },
}

# params

Custom parameters passed to templates.

params: {
  title: "My Site",
  author: "Your Name",
  description: "Site description",
  // Any custom data you need in templates
}

# Full Example

export default {
  extends: "book",

  rootUrl: "",
  uglyURLs: false,

  paths: {
    output: "dist",
    public: ["images", "downloads"],
  },

  serve: {
    reload: true,
    port: 3000,
    wsPort: 3001,
  },

  params: {
    title: "My Documentation",
    author: "Your Name",
    description: "Comprehensive guide",
    rightToc: {
      enabled: true,
      title: "On this page",
      minHeadings: 2,
      levels: [2, 3],
    },
  },
};

site-config.md

# Site Config

The config.ts file is the heart of your bok site. This page covers all configuration options in detail.

# Config Structure

export default {
  // Theme to extend
  extends?: string,

  // URL prefix
  rootUrl?: string,

  // URL style
  uglyURLs?: boolean,

  // Directory paths
  paths?: {
    content?: string,
    output?: string,
    assets?: string,
    layout?: string,
    defaultLayout?: string,
    public?: string[],
  },

  // File discovery
  files?: {
    type: "walk" | "glob" | "toc",
    file?: string,  // for toc type
    glob?: string,  // for glob type
  },

  // Dev server
  serve?: {
    reload?: boolean,
    port?: number,
    wsPort?: number,
  },

  // Lifecycle hooks
  hooks?: {
    beforeSite?: Function,
    afterSite?: Function,
    beforePage?: Function,
    afterPage?: Function,
  },

  // Custom data for templates
  params?: Record<string, any>,
};

# Path Resolution

All paths in the config are resolved relative to the config file's directory.

// If config is at /home/user/my-site/config.ts
paths: {
  content: "content",     // → /home/user/my-site/content
  output: "../docs",      // → /home/user/docs
  public: ["images"],     // → /home/user/my-site/images
}

# Extending Themes

When you extend a theme:

  1. Theme's hooks are used
  2. Theme's paths.assets and paths.layout are used
  3. Theme's files config is used (if not overridden)
  4. Theme's params are merged with yours (yours take precedence)
// Theme config
params: {
  title: "Default Title",
  showToc: true,
}

// Your config
params: {
  title: "My Title",  // Overrides theme
  author: "Me",       // Added
  // showToc: true    // Inherited from theme
}

# File Discovery Modes

# TOC Mode

Best for books and documentation with a specific reading order.

files: {
  type: "toc",
  file: "toc.md",  // Relative to content directory
}

The toc.md file defines:

  • Page order
  • Navigation structure
  • Section groupings

See TOC Format for details.

# Walk Mode

Recursively finds all markdown files.

files: {
  type: "walk",
}

Good for blogs or sites without strict ordering.

# Glob Mode

Find files matching a pattern.

files: {
  type: "glob",
  glob: "posts/**/*.md",
}

# Hooks

Hooks let you customize the build process.

# beforeSite

Called once before any pages are processed.

hooks: {
  async beforeSite(site, pages, opts) {
    // Generate sitemap data
    // Set up shared resources
    console.log(`Building ${pages.length} pages`);
  },
}

# afterSite

Called once after all pages are processed.

hooks: {
  async afterSite(site, pages, opts) {
    // Generate sitemap.xml
    // Generate RSS feed
    // Post-process output
  },
}

# beforePage / afterPage

Called for each page.

hooks: {
  async beforePage(site, page, index, pages, opts) {
    // Modify page before rendering
    page.params.buildTime = new Date().toISOString();
  },

  async afterPage(site, page, index, pages, opts) {
    // Post-process individual page
  },
}

# Params

The params object is passed to all templates. Use it for:

  • Site metadata (title, author, description)
  • Theme configuration
  • Custom data
params: {
  // Metadata
  title: "My Site",
  author: "Your Name",
  description: "Site description",
  url: "https://example.com",

  // Theme options
  rightToc: {
    enabled: true,
    title: "Contents",
    levels: [2, 3, 4],
  },

  // Custom data
  socialLinks: {
    github: "https://github.com/you",
    twitter: "https://twitter.com/you",
  },
}

toc-format.md


## Elements

### Headers

Create section titles that appear in the sidebar.

```markdown
# Getting Started

# API Reference

# Advanced Topics

# Links

Top-level links without list markers.

[Introduction](index.md)
[About](about.md)

# List Items

Numbered chapters with nesting support.

- [Chapter 1](chapter-1.md)
  - [Section 1.1](section-1-1.md)
  - [Section 1.2](section-1-2.md)
- [Chapter 2](chapter-2.md)

Renders as:

  • 1. Chapter 1
    • 1.1. Section 1.1
    • 1.2. Section 1.2
  • 2. Chapter 2

# Horizontal Rules

Visual separators between sections.

- [Chapter 1](chapter-1.md)

---

# New Section

- [Chapter 2](chapter-2.md)

# Draft Pages

Empty parentheses create a draft entry (no link).

- [Coming Soon]()

This appears in the sidebar but isn't clickable.

# Full Example

# My Book

[Introduction](index.md)

- [Getting Started](getting-started.md)

---

# Core Concepts

- [Installation](install.md)
  - [macOS](install/macos.md)
  - [Linux](install/linux.md)
  - [Windows](install/windows.md)

- [Configuration](config.md)
  - [Basic Setup](config/basic.md)
  - [Advanced Options](config/advanced.md)

---

# API Reference

- [Functions](api/functions.md)
- [Types](api/types.md)
- [Examples](api/examples.md)

---

# Appendix

- [FAQ](faq.md)
- [Changelog](changelog.md)
- [Contributing](contributing.md)

# File Paths

Paths are relative to the content/ directory.

# If content/ structure is:
# content/
#   index.md
#   guide/
#     intro.md
#     advanced.md

[Home](index.md)
- [Intro](guide/intro.md)
- [Advanced](guide/advanced.md)

# Navigation

The TOC automatically generates:

  • Left sidebar - Full navigation tree
  • Previous/Next links - Based on page order
  • Active highlighting - Current page is highlighted

Pages are ordered exactly as they appear in the TOC file.


Front Matter

# Front Matter

Front matter lets you add metadata to individual pages.

# Syntax

Add key-value pairs at the top of your markdown file, followed by ---:

title: My Page Title
layout: custom.ts
author: John Doe
---

# Page Content

Your markdown content here...

# Available Properties

# layout

Override the default layout template for this page.

layout: my-layout.ts

The path is relative to the layout/ directory.

# Custom Properties

Add any custom properties you need:

title: Getting Started
description: Learn how to get started with bok
author: Your Name
date: 2024-01-15
tags: tutorial, beginner
draft: true
---

Access these in templates via page.params:

export default function(site, page, pages) {
  return `
    <article>
      <h1>${page.params.title}</h1>
      <p>By ${page.params.author}</p>
      ${page.htmlContent}
    </article>
  `;
}

# Parser Details

The front matter parser:

  • Reads lines until it hits ---
  • Splits each line on the first :
  • Trims whitespace from keys and values
  • All values are strings
key: value with spaces
another: value: with: colons
---

Results in:

{
  key: "value with spaces",
  another: "value: with: colons"
}

# Examples

# Blog Post

title: My First Post
date: 2024-01-15
author: Jane Doe
tags: announcement, news
---

# Welcome to My Blog

This is my first post...

# Custom Layout

layout: landing.ts
---

# Welcome

This page uses a custom landing page layout.

# Documentation Page

title: API Reference
description: Complete API documentation
order: 5
---

# API Reference

...

# No Front Matter

Front matter is optional. If omitted, the page uses:

  • Default layout from config
  • Empty params object
# Just Content

This page has no front matter.

themes.md

# Themes

Themes control the look and feel of your bok site. They provide layouts, styles, and default configuration.

# Built-in Themes

# basic

A minimal theme with just the essentials.

export default {
  extends: "basic",
};

Features:

  • Simple HTML structure
  • No styling
  • Good starting point for custom themes

# book

A documentation theme inspired by mdBook and GitBook.

export default {
  extends: "book",
};

Features:

  • Sidebar navigation
  • Previous/next page links
  • Right-side table of contents
  • Responsive design
  • Syntax highlighting

See Book Theme for details.

# Theme Structure

A theme consists of:

my-theme/
├── config.ts       # Theme configuration
├── layout/         # Template files
│   ├── index.ts    # Default layout
│   └── base.ts     # Base HTML wrapper
├── assets/         # Static assets
│   ├── css/
│   ├── js/
│   ├── img/
│   └── fonts/
└── content/        # Example content (for init)
    ├── toc.md
    └── index.md

# Extending vs Creating

# Extend (Recommended)

Use the theme's layouts and assets, customize only what you need:

export default {
  extends: "book",
  params: {
    title: "My Docs",
  },
};

# Create

Copy theme files for full customization:

bok init --mode create --theme book

This copies all theme files to your project.

# Custom Themes

Create your own theme by:

  1. Creating a theme directory with the structure above
  2. Writing a config.ts with theme defaults
  3. Creating layout templates
  4. Adding assets

Reference your custom theme:

export default {
  extends: "/path/to/my-theme/config.ts",
};

See Creating Themes for a complete guide.


book-theme.md

# Book Theme

The book theme provides a complete documentation experience similar to mdBook or GitBook.

# Features

  • Sidebar navigation - Collapsible table of contents
  • Page navigation - Previous/next page arrows
  • Right TOC - On-page heading navigation with scroll spy
  • Responsive - Works on mobile and desktop
  • Syntax highlighting - Via Prism.js
  • Toggle sidebar - Hide/show for more reading space

# Configuration

# Basic Setup

export default {
  extends: "book",

  params: {
    title: "My Documentation",
    author: "Your Name",
    description: "Project documentation",
  },
};

# Right Table of Contents

Configure the on-page heading navigation:

params: {
  rightToc: {
    enabled: true,        // Show/hide right TOC
    title: "On this page", // Section title
    minHeadings: 2,       // Minimum headings to show TOC
    levels: [2, 3],       // Which heading levels to include
  },
}

# Layout Structure

The book theme uses two layout files:

# base.ts

The HTML wrapper with:

  • Document head (meta, CSS, fonts)
  • Script includes
  • Body wrapper

# index.ts

The page structure:

  • Sidebar with TOC
  • Main content area
  • Previous/next navigation
  • Right-side TOC

# Styling

# CSS Files

File Purpose
reset.css CSS reset
variables.css CSS custom properties
base.css Core layout styles
typography.css Text and heading styles
list.css List styling
prism.css Code highlighting

# CSS Variables

Customize colors by overriding CSS variables:

:root {
  --bg: #ffffff;
  --fg: #333333;
  --sidebar-bg: #f5f5f5;
  --link-color: #0066cc;
}

# JavaScript

# index.js

Handles:

  • Sidebar toggle
  • Keyboard navigation (left/right arrows)
  • Session storage for sidebar state

# prism.min.js

Syntax highlighting for code blocks.

# Keyboard Shortcuts

Key Action
← Previous page
→ Next page
s Toggle sidebar

# File Discovery

The book theme uses TOC mode by default:

files: {
  type: "toc",
  file: "toc.md",
}

Your content/toc.md defines the sidebar structure.

# Example Site

See the examples/book/ directory for a complete example site using this theme.


creating-themes.md

# Creating Themes

Build custom themes for your bok sites.

# Theme Structure

my-theme/
├── config.ts       # Required: theme configuration
├── layout/         # Required: template files
│   └── index.ts    # Required: default layout
├── assets/         # Optional: static files
└── content/        # Optional: example content

# Theme Config

Create config.ts:

export default {
  name: "my-theme",

  // File discovery mode
  files: {
    type: "walk",  // or "toc", "glob"
  },

  // Path defaults (relative to this file)
  paths: {
    assets: "assets",
    layout: "layout",
    defaultLayout: "index.ts",
  },

  // Dev server defaults
  serve: {
    reload: true,
    port: 5000,
    wsPort: 5001,
  },

  // Lifecycle hooks
  hooks: {
    async beforeSite(site, pages, opts) {},
    async afterSite(site, pages, opts) {},
    async beforePage(site, page, i, pages, opts) {},
    async afterPage(site, page, i, pages, opts) {},
  },

  // Default params (users can override)
  params: {
    title: "My Theme",
  },
};

# Layout Templates

Layouts are TypeScript files that export a function:

// layout/index.ts
export default function(site, page, pages) {
  return `
    <!DOCTYPE html>
    <html>
      <head>
        <title>${page.params.title || site.params.title}</title>
        <link rel="stylesheet" href="${site.rootUrl}/assets/css/style.css">
      </head>
      <body>
        <main>
          ${page.htmlContent}
        </main>
      </body>
    </html>
  `;
}

# Template Parameters

# site

The site configuration object:

site.rootUrl      // URL prefix
site.params       // Site params from config
site.paths        // Directory paths
site.uglyURLs     // URL style boolean

# page

The current page being rendered:

page.name         // Filename
page.path         // Full file path
page.link         // URL path (e.g., "/getting-started")
page.params       // Front matter data
page.htmlContent  // Rendered markdown HTML
page.tokens       // markdown-it AST tokens
page.toc          // Left sidebar HTML (if using TOC mode)
page.rightToc     // Right-side TOC HTML
page.prevPage     // Previous page URL
page.nextPage     // Next page URL

# pages

Array of all pages in the site.

# Composable Templates

Split templates into reusable parts:

// layout/base.ts
export default function({ title, rootUrl }, content) {
  return `
    <!DOCTYPE html>
    <html>
      <head>
        <title>${title}</title>
        <link rel="stylesheet" href="${rootUrl}/assets/css/style.css">
      </head>
      <body>
        ${content}
      </body>
    </html>
  `;
}

// layout/index.ts
import base from "./base.ts";

export default function(site, page, pages) {
  return base(
    { title: page.params.title, rootUrl: site.rootUrl },
    `<main>${page.htmlContent}</main>`
  );
}

# Assets

Place static files in assets/:

assets/
├── css/
│   └── style.css
├── js/
│   └── main.js
├── img/
│   └── logo.svg
└── fonts/
    └── ...

Reference in templates:

`<link rel="stylesheet" href="${site.rootUrl}/assets/css/style.css">`
`<script src="${site.rootUrl}/assets/js/main.js"></script>`

# Hooks

Use hooks for advanced processing:

hooks: {
  // Generate sitemap after build
  async afterSite(site, pages, opts) {
    const sitemap = pages
      .map(p => `<url><loc>https://example.com${p.link}</loc></url>`)
      .join("\n");

    await Bun.write(
      `${site.paths.output}/sitemap.xml`,
      `<?xml version="1.0"?><urlset>${sitemap}</urlset>`
    );
  },

  // Add build timestamp to each page
  async beforePage(site, page, i, pages, opts) {
    page.params.buildTime = new Date().toISOString();
  },
}

# Using Your Theme

Reference by path:

export default {
  extends: "/path/to/my-theme/config.ts",
  params: {
    title: "My Site",
  },
};

Or initialize with it:

bok init --mode extend --theme path --theme-path /path/to/my-theme/config.ts

contributing.md

# Contributing

Contributions to bok are welcome!

# Development Setup

# Clone the repository
git clone https://github.com/alajmo/bok
cd bok

# Install dependencies
bun install

# Run the example site
make serve-debug

# Project Structure

bok/
├── mod.ts              # CLI entry point
├── deps.ts             # Centralized dependencies
├── src/
│   ├── mod.ts          # Main exports
│   ├── core/
│   │   ├── build.ts    # Build pipeline
│   │   ├── config.ts   # Configuration loading
│   │   ├── init.ts     # Site initialization
│   │   ├── server.ts   # HTTP server
│   │   ├── watch.ts    # File watching
│   │   ├── ws-server.ts # WebSocket server
│   │   └── utils.ts    # Utilities
│   └── plugins/
│       └── toc.ts      # TOC parser
├── themes/
│   ├── basic/          # Minimal theme
│   └── book/           # Documentation theme
└── examples/
    └── book/           # Example site

# Key Files

# deps.ts

All external dependencies are centralized here. This makes it easy to swap implementations.

# src/core/build.ts

The main build pipeline:

  1. Clean output directory
  2. Discover pages (walk/glob/toc)
  3. Process each page (front matter → markdown → template)
  4. Copy assets

# src/core/config.ts

Configuration loading and merging:

  • Read user config
  • Apply defaults
  • Merge with theme config
  • Validate paths

# src/plugins/toc.ts

Custom lexer and parser for the TOC format:

  • TocReader - Character stream
  • TocLexer - Tokenizer
  • TocParser - AST builder
  • TocRender - HTML generator

# Making Changes

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test with the example site
  5. Submit a pull request

# Testing

Run the example site to test changes:

# Development server
make serve-debug

# Build only
make build

# Code Style

  • TypeScript for all source files
  • Use template literals for HTML generation
  • Keep dependencies minimal
  • Prefer explicit over implicit

# Reporting Issues

Open an issue on GitHub with:

  • bok version
  • Bun version
  • Operating system
  • Steps to reproduce
  • Expected vs actual behavior
↑↓ navigate Enter select Esc close