Problem
The whole site is client-rendered. Every built page has an empty body:
dist/index.html
<body>
<div class="app-root"></div>
<div id="rtl-container" dir="rtl"></div>
</body>
All content — the h1, the docs tables, the recipe code — only exists after main-*.js executes and React mounts.
Why this matters
- Google can render JS, but rendering is queued separately from crawling and can lag by days; pages compete for a finite render budget. A 1.5 MB unminified bundle (see the bundle-size issue) makes each render expensive.
- Bing, DuckDuckGo, Yandex, and most LLM/AI crawlers (which increasingly drive docs traffic) render JS poorly or not at all. To them, every page on this site is blank.
- Social scrapers get nothing beyond the static
<meta> tags.
- LCP is gated on bundle download + parse + mount rather than on HTML.
For a documentation site this is the wrong tradeoff — the content is static and could be fully present in the HTML.
Suggested fix
The content is already React components with no runtime data dependencies (except three fetch calls for version/downloads stats in Header.tsx, which can stay client-side and hydrate in). So prerendering at build time is straightforward:
vite-plugin-prerender / vite-prerender-plugin — renders each entry in rolldownOptions.input to static HTML at build time, keeps the current architecture. Lowest-effort option.
react-dom/server in a small build step — call renderToString per page in tools/generate-recipe-html.mjs and inline the result into <div class="app-root">, then let the existing client bundle hydrate.
- A static-site framework (Astro etc.) — correct long-term, but a rewrite.
Option 1 or 2 gets the full docs into the HTML with no change to how components are authored.
Impact
High — compounds with every other content-level finding, since none of that content is in the served HTML today.
Problem
The whole site is client-rendered. Every built page has an empty body:
dist/index.htmlAll content — the h1, the docs tables, the recipe code — only exists after
main-*.jsexecutes and React mounts.Why this matters
<meta>tags.For a documentation site this is the wrong tradeoff — the content is static and could be fully present in the HTML.
Suggested fix
The content is already React components with no runtime data dependencies (except three
fetchcalls for version/downloads stats inHeader.tsx, which can stay client-side and hydrate in). So prerendering at build time is straightforward:vite-plugin-prerender/vite-prerender-plugin— renders each entry inrolldownOptions.inputto static HTML at build time, keeps the current architecture. Lowest-effort option.react-dom/serverin a small build step — callrenderToStringper page intools/generate-recipe-html.mjsand inline the result into<div class="app-root">, then let the existing client bundle hydrate.Option 1 or 2 gets the full docs into the HTML with no change to how components are authored.
Impact
High — compounds with every other content-level finding, since none of that content is in the served HTML today.