snappy-prerender - Turn your existing SPA into static HTML

by•
snappy-prerender opens every route of your built SPA in a real browser at build time and writes static HTML. Keep your framework, router, build and deploy. Adds per-route SEO, sitemap, audit, hydration checks, CSP and preload hints.

Add a comment

Replies

Best
Maker
📌

Hey Product Hunt,

I maintain several apps: CRA, React 18, client-side routing, CMS content. SEO and OG tags need real HTML, and a client-side app gives crawlers an empty page.

I built snappy-prerender as a replacement for react-snap to ease my headaches. It is now a framework-agnostic static site generator for apps you already have.

At build time it opens each route in a browser, follows links, writes static HTML, and checks that the client uses it. It also writes per-route SEO and sitemap data, audits the output, verifies hydration, and accepts routes from a file or sitemap. React, Vue, Svelte and Preact are supported. You keep your framework, router, build and deploy.

It is not SSR. New content needs a build. It is not for Next.js, Remix or Astro, and it will not fix pages that render differently on every load; it reports the route and first mismatch.

npm install --save-dev snappy-prerender
npx snappy-prerender init
npx snappy-prerender

Or run it from vite build with the Vite plugin. If you have an old SPA, React or not, try it and tell me what breaks.

Maker
  • One command after your normal build. Point it at dist, build, or any static output. No SSR entry, router migration, or app rewrite.

  • Real browser rendering. Every route is loaded in Chrome/Edge/Chromium, allowed to settle, then serialized to static HTML.

  • Hydration verification. Every written page is reloaded with the client bundle and reported as hydrated or re-rendered, with framework-specific errors and the first DOM mismatch.

  • SEO without React Helmet. Titles, descriptions, canonical, Open Graph, Twitter, JSON-LD, hreflang, arbitrary head tags, and html/body/title attributes — with restoration on client navigation.

  • Client-side head parity. Covers the React Helmet / Helmet Async surface for prerendered apps: defaultTitle, multiple images, duplicate metas, onChangeClientState, and React 19 native tag adoption.

  • Locales and hreflang. Path or single-locale builds, canonical URLs, og:locale, x-default, sitemap alternates, and cookie/localStorage SEO locale seeding.

  • Site audit. Broken internal links, metadata gaps, duplicate titles/descriptions, heading problems, sitemap disagreement, CSP violations, and orphan pages.

  • Faster static output. Critical CSS, inline CSS, HTML/CSS minification, preconnect hints, image preload, modulepreload, a preload manifest, and cached AJAX state.

  • Deterministic builds. Freeze time, set timezone, seed Math.random, and honour SOURCE_DATE_EPOCH so repeated builds stay stable.

  • Explicit hydration policies. Allow a re-render or skip verification for genuinely live routes instead of disabling the check globally.

  • Flexible route sources. Crawl, explicit routes, text/JSON files, sitemaps, route priorities, depth limits, and route overrides.

  • CI-friendly. Versioned JSON reports, audit gates, hydration gates, failure traces, screenshots, and authenticated route support.

  • Works with the stack you already have. React 16.8, 17, 18 and 19; Vite 6, 7 and 8 + CRA; Vue, Svelte and Preact; Angular, Solid, Lit, Ember, vanilla JavaScript, or any other client-rendered SPA.