Add Keystatic CMS integration - #74
Conversation
Add Keystatic as a CMS option alongside microCMS, scoped to Astro bases
(astro, astro-react, astro-vue) and excluded from Nuxt/Vite.
- Generate keystatic.config.ts with local storage (commented GitHub block)
- Mount the keystatic() integration in dev only; production build sets
SKIP_KEYSTATIC=true so the site stays fully static and needs no adapter
- Auto-inject the React renderer (Keystatic's admin UI is React-based)
- Re-key CMS templates by provider: templates/cms/{cms}/{group}
- Replace the hardcoded vite CMS guard with a registry-driven excludeGroups
check; add CMS.IsValidForBase and create-command validation/fallback
Code review — Keystatic feature (commit 9ec3861)Reviewed for correctness bugs, broken combinations, template-rendering edge cases, and microCMS regressions. Build/vet/tests pass; all generated 🟡 Worth fixing
🔵 By design — not bugs
🟢 Latent / low priority
Scope question (not a defect)
Suggested action: apply #1 + #2 + the #3 doc clarification (clear, low-risk wins); decide separately on the content pipeline. |
Move the React renderer packages and the SKIP_KEYSTATIC build-script override into the keystatic registry entry, and delete the Go cross-cutting rule. The cms merge runs after the base, so the build override applies via the registry. Keeps package versions in the registry single source of truth instead of duplicated in Go.
GetBase returns nil for an unrecognized base; dereferencing entry.Group would panic. Return an error instead, matching the nil-registry guard already in this method and the entry-nil checks in IsAstro/IsVite.
Review follow-upFixed (two commits):
Acknowledged, deferred (not fixing in this PR):
All three are future-maintainer concerns with no current reachable path; tracking here rather than fixing now. |
The jsx/jsxImportSource compiler options were gated on Base==astro-react, but Keystatic pulls in the React renderer on plain astro and astro-vue too. Gate on React being present (astro-react OR keystatic) so .tsx and astro check type-check correctly. Mirrors the astro.config integration condition.
Re-review (full diff vs main, tip 9c5350b → now e81260e)Independent high-effort re-review of the whole feature, including the two prior fixes. One new correctness bug found and fixed; everything else is already-tracked or non-issues. 🔴 Fixed — new bugJSX tsconfig options gated on the wrong condition — Fixed in e81260e: gate on
Already known / non-issues
Verifier refuted the higher-severity candidates: |
Scaffold already fetches and nil-guards the base entry at the top, so the CMS block can use entry.Group directly instead of re-deriving it via GetGroup — removing a redundant registry scan and an unreachable error path.
Re-review #3 (full diff vs main, tip e81260e → now c5db3aa)Independent high-effort pass over the whole feature. No new correctness bugs. One small cleanup applied; everything else is by-design or already-tracked. Applied — cleanup
Reviewed — not a bug (by design)
Maps to already-deferred items
Refuted (good signals)Verifier refuted the version-mismatch candidates again: Verdict: PR is solid; no outstanding correctness issues. Remaining items are the intentionally-deferred low-priority notes and the content-pipeline scope decision. |
1. Target
2. Specification / Test Plan
Adds Keystatic as a CMS option alongside microCMS.
Specification
astro,astro-react,astro-vue); excluded from Nuxt/Vite via the registry'sexcludeGroups(hidden in the wizard, warns + falls back tononein the CLI).keystatic.config.tsusing local storage (content as files in the repo), with a commented GitHub-mode block + docs link for switching later.keystatic()integration is mounted in dev only —...(process.env.SKIP_KEYSTATIC ? [] : [keystatic()]). The admin UI is served at/keystaticduringdev; the productionbuildscript setsSKIP_KEYSTATIC=trueso the site stays fully static and needs no server adapter. This means the existing Cloudflare deploy path is untouched.@astrojs/react+react/react-dom+ types) is auto-injected, since Keystatic's admin UI is React-based — even onastroandastro-vuebases.@keystatic/astro@5.1.0,@keystatic/core@0.5.50,cross-env@^10.1.0.Implementation notes
templates/cms/{cms}/{group}(existing microCMS files renamed undermicrocms/, history preserved viagit mv).scaffold.go: hardcoded "no CMS on vite" check replaced with a generic registry-drivenexcludeGroupsguard.CMS.IsValidForBasehelper + create-command validation/fallback.astro.config.mjs.tmplreworked for the new integration combinations (also fixes a latent missing-comma bug in the generated config).Test Plan
Automated (
go test ./..., all green):keystaticon plain astro injects the React renderer +cross-env/types.keystaticon astro-vue addsreact()alongsidevue().keystaticon astro-react does not duplicate React deps.buildscript =cross-env SKIP_KEYSTATIC=true astro build.CMS.IsValidForBasematrix (astro* → true, nuxt/vite → false).Manual (scaffolded real projects with the built binary):
keystatic.config.ts; all generatedastro.config.mjspassnode --check.none(no keystatic files emitted).3. Additional Instructions / Notes for Shipping (optional)
Keystatic + Cloudflare-managed deploy is intentionally not a special case — because production builds are static, the existing Cloudflare Pages/Workers flow works as-is. GitHub/Cloud storage modes are out of scope for this PR (documented switch path in the generated config).
4. Check before Review Request
5. Evidence
(Attach here before request review)