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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants