Vite React SPA SSG Setup

Job ID: 40175580

Budget: £250 – £750 GBP

Project Summary
We have a website built with Vite + React + TypeScript and deployed on Netlify. The site is currently a SPA, so “View Source” contains minimal HTML, and SEO crawlers don’t see page content without JS.
We need an engineer to implement build-time pre-rendering / static site generation so that every public marketing page is generated as a real .html file at build time and served directly by Netlify.

Target site:
https://nationalremovalsandstorage.co.uk/

Current Tech Stack
Frontend: React + TypeScript
Build: Vite
Routing: react-router-dom
Hosting: Netlify (GitHub deploy)
Backend/data: Supabase (some pages pull content from Supabase, e.g., testimonials/SEO data)
Existing build scripts: includes sitemap generation and a “prerender:locations” script (currently not producing full HTML pages reliably)
Netlify config includes redirects for dynamic location pages and SPA fallback.

Goals (Must Have)
1. Generate static HTML files for all SEO pages during build.
Result: When opening a URL like /house-removals and checking “View Page Source”, it should contain meaningful page text and headings (not an empty React shell).
2. Support all core routes, including:
/ (home)
/about
/services
/removals
/house-removals
/office-removals
/packing-services
/storage
/contact
/how-it-works
plus other public pages already in the repo (e.g. /blue-light-card, /mid-week-move, etc.)
3. Dynamic “location” pages must also be pre-rendered:
We have routes like:
/removals-:citySlug
/:serviceType-:citySlug
We want a build step that generates dist/removals-london.html, dist/house-removals-manchester.html, etc. for a list of locations/service combinations.
The location list may come from Supabase OR a JSON file committed to the repo (freelancer to propose best approach).
4. Netlify should serve the pre-rendered HTML file directly:
URLs should stay clean (no .html in the browser).
Netlify redirects/rewrites must map clean URLs to .html files where applicable, while keeping SPA fallback working for non-pre-rendered routes (admin/portal/auth).
5. Do not break portals/auth pages:
These must remain SPA-only:
/admin, /admin2, /temp-admin
/client-portal, /partner-portal, /trade-portal, /staff-portal
/login, /signup
6. Works on Netlify production builds and local dev.

What “Done” Looks Like (Acceptance Tests)
The freelancer must deliver a PR and demonstrate:
A) HTML content visible without JS
For each key page:
Open URL (e.g. /house-removals)
Right-click → View Page Source
Source includes:
<title> and meta tags
<h1> / main headings and real text content (not just <div id="root"></div>)
B) No 404s / correct routing
Direct visit to deep URL works (e.g. /storage from a fresh browser)
Internal navigation still works
SPA fallback still works for non-pre-rendered/private routes
C) Location pages generated and served
Sample set of 20+ location pages are generated in dist/ as .html
Netlify config routes clean URL → correct .html
“View Source” includes meaningful content.
D) Sitemap updated
sitemap.xml includes all static and generated location URLs.

Implementation Notes (What We Expect)
The freelancer can propose one of these approaches (or best fit):
vite-plugin-ssr / Vike
react-snap
puppeteer-based prerender script
prerender-spa-plugin
or a custom Node script that renders routes to HTML
But the solution must:
Be maintainable
Run in Netlify CI reliably
Not require paid third-party render services

Repo / Build Details
Build command currently: npm run build
Netlify publishes: dist
Node version currently set to 18 in Netlify, but can be upgraded to Node 20 if needed (Supabase warning suggests Node 20 is preferred).
Netlify redirects currently include mappings like:
/removals-:city → /removals-:city.html
plus SPA fallback /* → /index.html
Freelancer should refine/adjust this configuration based on the chosen solution.

Deliverables
1. PR with:
Pre-render build pipeline working
Updated scripts in package.json
Any new config/files (e.g., routes list / locations list)
Updated netlify.toml where required
2. Documentation (README section) explaining:
How prerender works
How to add new routes
How to add new locations
How to test locally
3. Proof:
Screenshots or short video showing “View Source” contains content for:
/
/house-removals
at least 2 generated location pages

Important Constraints
Must not expose any secrets in the repo.
If using Supabase during build to fetch location lists, use Netlify environment variables safely.
If Supabase isn’t available during build, use a committed JSON fallback list.
Avoid breaking existing UI/UX, portals, and auth flows.

Skills Required
React + TypeScript
Vite build pipeline
Netlify deploy configuration (redirects/rewrites)
Static rendering / SSG / prerendering
Node scripting (if using custom renderer)