Pre-rendering SEO Pages in a Vite SPA
Here is how the technical stuff works behind the scene for this.
The app is still a Vite + React project that runs as a PWA on the base route. I did not change that part at all. The interactive visualizer stays a client side app, and the pre rendered pages are kept completely separate from it.
I handled this with a small custom Vite setup that runs at build time.
All SEO pages live under src/pages/*. Each page exports a normal React component and a meta object. The idea of declaring metadata next to the page is inspired by the App Router, while routing itself is derived from the filesystem (similar to the Pages Router).
During the build, a prerender step walks the pages directory, renders each page using react-dom/server, and injects metadata, JSON LD, fonts, analytics, and CSS into a plain HTML template that comes from the main app build.
The HTML is emitted straight into Vite’s build output directory (outDir) using the route derived from the file structure, for example outDir/algorithm/bfs.html.
In development, the same logic is hooked into the dev server so these pages can be previewed locally without changing how the app itself runs.
These pages are intentionally kept outside the PWA scope and service worker. They are just static HTML with no hydration or client side routing. Their only job is to be crawlable, linkable, and then funnel users into the actual visualizer with the right algorithm preselected.
I am curious how others would approach this, but it was fun to experiment with Claude Code to get this prerender pipeline working. It solves one very specific problem instead of trying to solve everything, which is usually where meta frameworks make more sense.
You can check out the code here: https://github.com/lakbychance/graphisual/blob/main/plugins/vite-plugins/prerender.ts
Lakshya Thakur
• 4mo
Graphisual is a SPA, which means it does not offer much crawlable text for search engines. To work around that, I added pre-rendered pages for individual algorithms and linked them from the algorithm selection inside the app.
These pages mainly exist to help with search visibility and backlinks, while still taking users directly into the visualizer with the relevant algorithm preselected. I have tried to keep these pages minimal and aligned with the overall look and feel of the app, so they do not feel out of place from a UX point of view.
This decision came from Google Search Console data. People do search for things like “Dijkstra visualizer”, and Graphisual already shows up for those queries, just at lower positions. The hope is that this improves rankings over time.
Let’s see how it goes 🤞
Your upvotes and feedback are welcome!
Words have more power than we think. Be kind.