Skip to content

Build the docs site: Fumadocs static export fed by sqlc-dev/sqlc docs/ - #1

Merged
kyleconroy merged 5 commits into
mainfrom
claude/coding-session-p6butr
Aug 27, 2026
Merged

Build the docs site: Fumadocs static export fed by sqlc-dev/sqlc docs/#1
kyleconroy merged 5 commits into
mainfrom
claude/coding-session-p6butr

Conversation

@kyleconroy

@kyleconroy kyleconroy commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

This repo now builds docs.sqlc.dev from the plain-Markdown content in sqlc-dev/sqlc docs/, keeping the Read the Docs URL scheme byte-for-byte so nothing changes for existing links.

What's here

  • Fumadocs on Next.js with output: 'export' — the build emits plain static files. Scaffold extras kept: Orama search (build-time index, queried in the browser), llms.txt / llms-full.txt, per-page raw Markdown routes with a Copy Markdown button, and build-time OG images.
  • Ingest step (scripts/ingest.mjs): checks out sqlc docs (or takes --src), derives each page's frontmatter title from its single # heading, converts toc.yaml into the sidebar meta.json (sections → separators, unlisted pages routable but out of the sidebar), and fails loudly on anything the content contract doesn't allow — that's the contract-drift alarm. Ingested pages stay .md, so fumadocs-mdx compiles them as Markdown, not MDX: literal {...} / <...> in prose (which the Go linter rightly permits) renders as written.
  • Contract shims: lib/remark-github-alerts.ts maps > [!NOTE]-style alerts to Callouts; lib/relative-link.tsx resolves relative .md links — bare ones included — to routes at render time, anchors intact.
  • RTD URLs are canonical, not redirected: pages are routed with the .html suffix under /en/latest, so /en/latest/howto/select.html is the page itself. Versioned builds mount at /en/vX.Y.Z (same scheme RTD used for tags), set noindex, and a sidebar switcher reads a runtime-fetched /versions.json so old snapshots list new versions. The only redirects left: / and /en//en/latest/, plus the old rediraffe upload → push rule.
  • Export post-processing (scripts/fix-html-ext.mjs): for a .html-suffixed route Next writes select.html.html plus a per-segment prefetch directory squatting on the page's own path. The script renames the page to the key its URL names and moves the segment dirs to out-segments/ — object storage holds both key shapes (flat keyspace, zero-404 prefetching); filesystem hosts fall back to the full-page RSC payload, which works.
  • CI (ci.yml): ingest + build + typecheck on every PR and push to main, uploading the built site as a site-preview artifact (serve locally with python3 -m http.server, open /en/latest/).

Generated output (content/, out*/, .source/) is never committed.

Verified

  • Build green from sqlc@main: all 41 pages (3 unlisted), search index, OG images, markdown routes.
  • Headless-browser click-through against a domain-shaped tree: initial loads at exact legacy URLs, client-side navigation between .html routes, cross-page anchors (/en/latest/reference/config.html#database), root redirect, versioned build with prefixed assets + noindex.

Not in this PR

Deployment automation (hosting is still to be decided — the README describes what a deploy needs to do), the dispatch workflow on the sqlc side, and DNS cutover.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Thc5nWNbxfQ67pVDcNSkxC

claude added 5 commits August 26, 2026 21:03
Scaffold a Fumadocs (Next.js static export) site mounted at the domain
root, plus everything around it:

- scripts/ingest.mjs: checks out sqlc docs (or takes --src), derives
  frontmatter titles from each page's # heading, converts toc.yaml into
  the sidebar meta.json (sections as separators, unlisted pages kept out
  of the sidebar), and fails loudly on contract drift
- pages stay .md so fumadocs-mdx compiles them as Markdown, not MDX;
  literal {...} and <...> in prose render as written
- lib/remark-github-alerts.ts maps GitHub alert blockquotes to Callouts;
  lib/relative-link.tsx resolves relative .md links (bare ones included)
  to routes at render time
- versioned builds via NEXT_PUBLIC_BASE_PATH with noindex and a
  version switcher driven by a runtime-fetched /versions.json
- scripts/redirects.mjs emits meta-refresh stubs for the legacy
  Read the Docs /en/latest/*.html URLs and the old rediraffe rule
- workflows: CI build on PRs, latest deploy on repository_dispatch/cron,
  tag deploys that sync to a version prefix and append versions.json

Generated output (content/, out/, .source/) is never committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Thc5nWNbxfQ67pVDcNSkxC
Nothing changes for existing links — they serve content directly instead
of redirecting:

- the latest build mounts at /en/latest (default basePath), versioned
  builds at /en/vX.Y.Z, matching RTD's tag URLs
- page routes carry the .html suffix via a custom loader url, so every
  internal link, sidebar entry, and search result points at the exact
  legacy URL (/en/latest/howto/select.html) and the exported file is the
  page itself — no edge rewrite rules needed
- scripts/fix-html-ext.mjs renames Next's <route>.html.html exports and
  moves the per-segment prefetch dirs (which squat on the page's own
  path) to out-segments/; object storage holds both key shapes, and
  filesystem hosts fall back to the full-page RSC payload
- redirects shrink to: / and /en/ → /en/latest/, plus the carried-over
  upload → push rule, all generated into out-root/ for the bucket root
- version switcher and workflows updated for the /en/<version> prefixes;
  only /en/latest is indexable

Verified with a headless-browser click-through: client-side navigation,
anchored cross-page links, and versioned builds all work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Thc5nWNbxfQ67pVDcNSkxC
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Thc5nWNbxfQ67pVDcNSkxC
Hosting is still to be decided; CI keeps building and uploading the
site-preview artifact. The README describes what a deploy needs to do
when the hosting choice lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Thc5nWNbxfQ67pVDcNSkxC
reference/changelog.md becomes a release index at its original URL, with
each release at reference/changelog/vX.Y.Z.html: title from the release
heading, subsections promoted one level, a 'Released <date> · View on
GitHub' line, and the leftover MyST anchor targets ((v1-31-1)=) dropped.

Fumadocs resolves an extensionless meta.json item to a folder before a
page, so the sidebar entry now references reference/changelog.md
explicitly — a single Changelog link, with the 37 release pages routable
but out of the sidebar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Thc5nWNbxfQ67pVDcNSkxC
@kyleconroy
kyleconroy merged commit 7a50bb4 into main Aug 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants