Skip to content

SEO: site ships zero HTML content (CSR-only) — consider build-time prerendering #253

Description

@limonte

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:

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions