A small personal Markdown and git-powered wiki I wrote to teach myself Go. You can see it in action here.
I have old Node and Python versions of this as well for giggles.
See the releases page for a few pre-built binaries.
Here's how you can run this from source or with the binary respectively:
# --- From Source ---
git clone https://github.com/afreeorange/bock.git
cd bock
# Build mode: generate a static wiki
go run --tags "fts5" . build --in=/path/to/repo --out=/path/to/output
# Serve mode: build + live-reload dev server for local writing and development
go run --tags "fts5" . serve --in=/path/to/repo --out=/path/to/output
# --- Using the pre-built binary ---
bock build --in=/path/to/repo --out=/path/to/output
bock serve --in=/path/to/repo --out=/path/to/outputAdd --help to see all options.
One-shot static site generation. Reads a git repository of Markdown files, renders everything to HTML, and exits.
bock build --in=<path> --out=<path> [options]Options:
--in=<path>โ Path to article repository (required)--out=<path>โ Output directory (required)--with-json-filesโ Generate JSON alongside HTML--with-raw-markdown-filesโ Generate raw markdown source files--without-revisionsโ Skip git history (much faster)--using-disk-fsโ Use on-disk git instead of in-memory clone
Builds the wiki and starts a dev server with WebSocket-based live reload. Revisions are always skipped in serve mode for speed.
bock serve --in=<path> --out=<path> [options]Additional options:
--port=<number>โ Port to serve on (default 8080)--theme=<path>โ Theme directory on disk (defaults to./theme/if present.)
The server watches both the article repository and the theme directory. When files change:
- Article changes (
.mdfiles) โ incrementally rebuild that article only - Theme template changes (
.tsx) โ re-compile the engine and re-render all pages concurrently - Static asset changes (
static/{css,js,img}) โ copy to output without re-rendering
The build command generates the following (using this article as an example):
- Every Markdown article in your repository rendered as HTML, Raw Markdown, and JSON
- A listing of all revisions for each article, if applicable. Some articles can be untracked and they will be annotated as such.
- Each article's revision rendered as HTML and Raw Markdown
- Each folder's structure in HTML and JSON
- An archive page with full-text search via SQLite and SQL.js
- A Homepage at
/Home - A page that redirects to a random article at
/random - A 404 Page at
/404.html
An Entity is either
- An Article, a Markdown file ending in
.mdsomewhere in your article repository, or - A Folder, which is exactly what you think it is. You can organize your articles into folders at any depth.
- A Revision, which is a
gitcommit that modifies an Article.
Other stuff:
- The name of the Markdown file is the title of the article and will be served at a simplified URI with underscores. For example,
/Notes on Photography.mdwill be served at/Notes_on_Photography/Tech Stuff/OpenBSD/pf Notes.mdwill be served at/Tech_Stuff/OpenBSD/pf_Notes
- The root of the generated wiki will always redirect to
/Home(for now) so you will need aHome.md.- You'll be warned if you don't have one.
- It will be generated if you don't have one.
- The paths
raw,revisions,random, andarchiveare reserved. So, for example, don't create araw.mdanywhere. It will be overwritten. - You can place static assets in
__assetsin your article repository. You can reference all assets in there in your Markdown files prefixed with/assets(e.g.__assets/some-file.jpgโ/assets/some-file.jpg). Here's an example. - Any dotfiles or dotfolders are ignored when generating the entity-tree.
- This includes
node_modules. See this file for other things. It's a small list.
- This includes
All page templates and components live in theme/ as TSX and other files. Here's the required stucture (TODO: enforce this.)
theme/
pages/ # Page templates (one per route type)
components/ # Shared components (Base, Nav, Footer, etc.)
static/ # CSS, JS, images served as-is
tsconfig.json # IDE type checking via Preact
globals.d.ts # Types for Article, Revision, etc.
Templates are pure function components โ no hooks, no state, no lifecycle methods. They are compiled at startup by ESBuild (via Go's ESBuild API) and rendered server-side in goja (a Go JS runtime) using Preact + preact-render-to-string.
Two helper functions are injected as globals:
formatDate(isoString, goLayout)โ formats an ISO date using Go's time layout syntaxhumanizeNumber(n)โ formats a number with commas (e.g.1,234,567)
NOTE: Run the build first and then serve for complete theme development.
The Preact runtime is pre-bundled at tsx/preact.js and embedded into the binary via go:embed. To rebuild it (e.g. after upgrading Preact), install preact and preact-render-to-string via NPM, then bundle with esbuild:
npm init
npm i preact preact-render-to-string
cat > tsx/preact-entry.js <<EOF
import { h, Fragment } from "preact";
import { renderToString } from "preact-render-to-string";
export { h, Fragment, renderToString };
EOF
npx esbuild tsx/preact-entry.js \
--bundle \
--format=iife \
--global-name=__preact \
--target=es2015 \
--platform=neutral \
--outfile=tsx/preact.js
echo 'var h=__preact.h,Fragment=__preact.Fragment,renderToString=__preact.renderToString;' > tsx/preact.jsmain.go CLI: parse flags, dispatch to build/serve
build.go Build orchestration, serve mode, re-render logic
renderers.go Markdown (goldmark) + TSX (Preact/goja) rendering
writers.go File and database output
tsx/
engine.go Compiles TSX via esbuild, renders via goja
engine_test.go Unit tests for the rendering engine
preact.js Bundled Preact runtime (go:embed-ed into binary)
preact-entry.js Entry file for rebuilding preact.js (not bundled)
server/
server.go HTTP server, WebSocket hub, fsnotify file watcher
reload.js Client-side script: reconnects + reloads on message
npx @tailwindcss/cli \
-i ./theme/static/css/main.css \
-o ./theme/static/css/styles.css \
--watchIf it's just CSS editing:
npx @tailwindcss/cli \
-i ./theme/static/css/main.css \
-o ~/Programming/wiki.nikhil.io.articles/build/css/styles.css \
--watch
# And then
cd Programming/wiki.nikhil.io.articles/build
lr-http-server