SE-62 Server-render top-level content on /options/ API reference pages - #7469
SE-62 Server-render top-level content on /options/ API reference pages#7469taktran wants to merge 4 commits into
Conversation
The property reference under /charts/options/ was rendered entirely client-side (client:only React fetching resolved-interfaces.json), so the served HTML had no H1 and no property content. Non-JS crawlers, including most AI assistants, saw an empty page. Add a server-rendered fallback (Astro slot="fallback") that emits the H1, interface description, and a flat list of top-level properties (name, type, default, description) from the same generated reference, reusing the existing framework-agnostic helpers. Nested children and deep type signatures stay client-rendered, keeping the added HTML small (~37KB on the largest page) per SE-53. Astro replaces the fallback with the interactive React island on hydration, so behaviour is unchanged.
|
✅ Codex review complete; 1 issue found (P0: 0 | P1: 0 | P2: 1 | P3: 0) View full reviewSE-62 Server-render top-level content on /options/ API reference pagesPR: #7469 SummaryAdds server-rendered, top-level options reference content as a fallback for crawlers and passes it into the interactive API reference pages. FindingsP0: 0 | P1: 0 | P2: 1 | P3: 0 1 inline comments posted. VerdictAssessment: correct The fallback is implemented safely and integrated into both affected pages; the only identified issue is malformed definition-list semantics for undocumented members. Required Actions: None - ready to merge |
Live-test this PR in PlunkerPaste these two <script src="https://ag-grid.github.io/ag-charts/pr-7469/ag-charts-community.min.js"></script>
<script src="https://ag-grid.github.io/ag-charts/pr-7469/ag-charts-enterprise.min.js"></script>Bundles are removed automatically when the PR is closed. Updated on every push. |
The server-rendered fallback rendered as a bare full-width block while the hydrated ApiReferencePage lays out inside a centred layout-grid with a left-nav column, so the body jumped horizontally (and, on mobile, vertically) on hydration. Mirror the hydrated two-column geometry in the fallback: wrap it in layout-grid, reserve the left-nav width with an empty placeholder column, and offset the content column using the same width tokens and breakpoints as objectViewOuter / referenceOuter. Also reserve the mobile search-box height so content does not drop when the nav appears. Verified zero shift across mobile, medium and large viewports.
Undocumented members produced a definition-list group with a <dt> but no <dd>, which is invalid dl semantics for assistive tech. Always emit the <dd> and drop its top margin when empty so undocumented rows gain no visual gap. Addresses Codex P2 review comment.
Rename OptionsReferenceFallback -> ApiReferenceFallback (it is generic over rootInterface) and wire it into themes-api.astro and the overrides nested page, so the Themes API reference gets the same crawlable server-rendered top-level content and layout-shift-safe fallback as /options/. Verified: /themes-api/ renders AgChartTheme with its top-level members and zero fallback-to-React shift; /options/ pages unchanged after the rename.
|
Still needs more testing before we merge this |
Summary
Closes the SEO/GEO discovery gap on the ~75
/charts/options/API reference pages (SE-62).Today these pages render the entire property reference client-side (
<ApiReferencePage client:only="react">fetching a 3.5MBresolved-interfaces.json). The served HTML has no<h1>and no property content — the reference only exists inside a<script>block that JS turns into the page. Googlebot runs JS so pages eventually index, but the first-pass crawl reads an empty page and most AI assistant crawlers don't run JS at all, so the API reference is invisible to them.Approach
Astro renders
slot="fallback"content of aclient:onlyisland into the served HTML and swaps it for the React app on hydration. This PR uses that to inject real, crawlable content without touching the React path:OptionsReferenceFallback.astro— a server-only component that reads the reference via the existinggetInterfacesReference()and emits the<h1>, interface description, and a flat list of top-level properties (name, type, default value, description), reusing the existing framework-agnostic helpers (processMembers,normalizeType,parseJsDocs,cleanupName).options.astroandoptions/[...memberName]/[type].astroasslot="fallback"on the existing island.Deep nested type signatures / child properties stay client-rendered (as guided on the ticket) — this keeps the added HTML small and honours the 2MB target from SE-53.
Why not full SSR of the React island
Astro serialises island props into the HTML for hydration; passing the 3.5MB reference (or the closure hydration would need) blows the 2MB budget, and partial data causes React hydration mismatches. The fallback slot sidesteps both, and keeps a single data source with no duplication of the recursive React logic.
Verification
Verified via a direct Astro render (dev server):
/options/served HTML now contains<h1>AgChartOptions</h1>+ 90 top-level property rows as real text./options/axes/radius-number/renders the correct variant H1axes.key[type='radius-number']+ 36 rows.<astro-island>→ cleanly replaced by React on hydration (no duplicate content); the client data file serves200, so the interactive view renders as before.nx format✅ ·nx lint ag-charts-website✅ (0 errors) · no render/hydration warnings.Notes / follow-ups
nx build/e2ewere not run here — this checkout has a pre-existing, unrelated failure (ag-charts-generate-example-filescan't resolve_ag-charts-test). Please run e2e in a clean environment before merge.react-markdownis React-only). Fine for crawlers and keeps the zero-dependency rule; the hydrated React view still renders full markdown.