-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
The site ships an empty <div id="root"></div> — all content is rendered client-side by JavaScript. Crawlers that don't execute JS (Bing, social media scrapers, AI indexers) see no content. Googlebot does execute JS but indexes it on a slower second pass, making it less reliable.
Recommendation
Pre-render the React app to static HTML at build time. Since this is a portfolio with no dynamic data, the entire page can be rendered once during npm run build and shipped as fully-formed HTML that hydrates into the interactive SPA on load.
Approach
Add a simple prerender script that:
- Imports the App component in a Node/SSR context
- Calls
renderToString(<App />)fromreact-dom/server - Injects the resulting HTML into the
<div id="root">in the builtindex.html - Runs as a post-build step
The entry point (main.tsx) would switch from createRoot + render to hydrateRoot so React attaches to the existing DOM rather than replacing it. All interactive features (X-ray, prism flip, confetti, cursor glow) continue to work after hydration.
Considerations
- The imperative DOM modules (
xray.ts,confetti.ts,coinCollect.ts) don't run during SSR — they only attach listeners on mount, so no changes needed useTypewriterstarts with an empty string and animates in — this is fine, the SSR output just shows the initial empty state and the animation plays on hydrate- The
window/documentreferences in hooks need to be guarded or only run inuseEffect(which doesn't fire during SSR) — audit for any top-level browser API access - Alternatively, consider
vite-plugin-prerenderorvite-ssginstead of a custom script
Depends on
This is independent of but complementary to adding meta tags to <head>. Meta tags handle social previews and search metadata; SSG handles content indexing.
Priority
Medium — the correct architectural fix for SEO, but lower urgency for a portfolio site that's primarily shared via direct links.