Skip to content

2026SoloFrontend

This site

Monochrome, bilingual, and prerendered enough that a link preview actually shows the right page.

This site

Overview

The site you are reading. React 18 on Vite 7 with Tailwind v4, deployed to Cloudflare Pages. Two languages on separate URL prefixes with hreflang alternates, a hand-set type scale rather than a generated ratio, and a grain overlay doing the work colour usually does. The sitemap is generated at build time and deliberately excludes anything unfinished. A post-build step prerenders every route — head and body — so link previews on WhatsApp and LinkedIn show the correct title and image, and crawlers that do not run JavaScript still read the full page.

The problem

A single-page app serves one HTML shell to every URL. Google renders JavaScript and copes, but social crawlers do not: every shared link showed the same generic preview card, and with two language prefixes there were suddenly six URLs all returning identical HTML to anything that could not execute JS.

What I did

Rather than adopt a prerender plugin — the ones commonly recommended were last released in 2022 — I wrote a post-build script that reads the built HTML and writes one copy per route with that route's title, meta, Open Graph tags, canonical, hreflang, and JSON-LD already inlined. It imports the translation file directly, so titles have exactly one source of truth. The body comes from Vite's own SSR build of the same route tree, rendered once per URL and hydrated in the browser. Zero new dependencies.

In the build

  • Two languages on separate URL prefixes with hreflang and canonical
  • Hand-set type scale: 13 / 15 / 17 / 21 / 28 / 44 / 76
  • Grain overlay and hairline rules instead of shadows
  • Sitemap generated at build, unfinished work excluded
  • Every route prerendered, head and body, then hydrated
  • JSON-LD structured data validated in Search Console
  • Local Docker parity with the Cloudflare rules

Stack

  • React 18
  • Vite 7
  • Tailwind 4
  • Framer Motion
  • Cloudflare Pages