orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1.PHONY: run build frontend images resume og clean
2
3# Geist ships .ttf inside the bun package, the only form Typst reads;
4# `make frontend` is what puts it on disk.
5GEIST = frontend/node_modules/geist/dist/fonts/geist-sans
6
7RESUME_DIR = resume
8RESUME_OUT = frontend/public/pdfs/resume-isaac-bythewood.pdf
9
10# Vite watches and rebuilds build/dist while Go serves it from disk. Templates
11# are embedded, so a template change needs a Go restart; CSS and JS changes only
12# need a browser reload, because a dev build never embeds the bundle.
13#
14# Go waits for the manifest rather than sleeping a guessed number of seconds.
15# The server treats a missing manifest as fatal, so the startup order matters,
16# and any fixed sleep short enough to be pleasant loses the race on a cold
17# build/dist.
18run:
19 cd frontend && bun run dev & \
20 i=0; while [ ! -f build/dist/.vite/manifest.json ]; do \
21 i=$$((i+1)); \
22 if [ $$i -gt 120 ]; then echo "vite did not produce a manifest in 60s" >&2; exit 1; fi; \
23 sleep 0.5; \
24 done; \
25 go run .
26
27frontend:
28 cd frontend && bun install --frozen-lockfile && bun run build
29
30# The resume PDF, compiled out of resume/ into publicDir so Vite copies it into
31# dist alongside the favicons. Skipped with a warning rather than a failure when
32# typst is absent, so a dev checkout serves a 404 for that one file and
33# everything else works.
34resume:
35 @if command -v typst >/dev/null 2>&1; then \
36 mkdir -p $(dir $(RESUME_OUT)); \
37 typst compile --root $(RESUME_DIR) $(RESUME_DIR)/resume.typ $(RESUME_OUT); \
38 echo "resume -> $(RESUME_OUT)"; \
39 else \
40 echo "typst not installed, skipping the resume PDF"; \
41 fi
42
43# The social card, compiled into publicDir so Vite copies it into dist beside
44# the favicons and the resume. Its own target for when only the card changed.
45og:
46 mkdir -p frontend/public/og
47 typst compile --format png --ppi 72 --font-path $(GEIST) typst/card.typ frontend/public/og/card.png
48
49# The release binary. -tags embed swaps assets_disk.go for assets_embed.go, so
50# the Vite bundle is compiled into the executable and ../../bin/<site> is the
51# whole deployable: one file, nothing beside it, no SITE_DIST to set.
52#
53# `frontend` is a requirement rather than ordering: the embed directive reads
54# build/dist at compile time.
55build: resume og frontend
56 go build -tags embed -trimpath -ldflags="-s -w" -o ../../bin/isaacbythewood.com .
57
58# Regenerate the responsive image ladder from frontend/images/. Part of `build`
59# so it cannot be forgotten, and its own target for when only the images
60# changed.
61images:
62 cd frontend && bun run images
63
64# build/ is everything this site generates. frontend/public/og and
65# frontend/public/pdfs are the exception, and stay where they are because Vite
66# copies publicDir into the bundle and only looks inside frontend/.
67clean:
68 rm -rf build frontend/node_modules frontend/public/og frontend/public/pdfs