Leon . Kang
Back to articles
Coding β€’ 3/5/2026 β€’ 8 min read

From Invisible to Readable: Why I Rebuilt My Site for the AI Era

Vite was great. Honestly, it still is.

Fast dev server, instant HMR, dead-simple config, React just works. When I built my personal site with Vite + React + TypeScript, it felt like the right call β€” modern, familiar, efficient. I had no real reason to change.

Then I started noticing something uncomfortable.

The Moment I Realized I Was Invisible

I was testing how AI assistants respond to questions about topics I'd written about. Things like SwiftUI multiplatform architecture, React rendering strategies, accessibility patterns β€” stuff I had actual posts on.

The AI either didn't know my content existed, or gave generic answers that had nothing to do with what I'd actually written.

So I pointed it to the site and asked directly: "What's written here?"

Nothing useful.

I tried fetching my own site the way a crawler would β€” a plain HTTP request, no JavaScript execution. What came back was essentially:

<div id="root"></div>

That's it. An empty shell. Everything I'd written β€” every post, every thought, every line of hard-won experience β€” lived entirely inside a JavaScript bundle that only a real browser could execute.

To a search crawler, I didn't exist. To an AI trying to read my site, I didn't exist. I had effectively disappeared from the web.

Why This Matters More Than SEO Ever Did

This isn't just a SEO problem. SEO was always a game you could play around β€” Google got smart enough to render JavaScript eventually.

But the shift happening now is different. People are increasingly going directly to AI assistants instead of search engines. They ask questions and get synthesized answers. The AI reads the web so the user doesn't have to.

If the AI can't read your content, you're not just ranking lower. You're not in the conversation at all.

I believe this gap will only widen. When someone asks an AI for a recommendation, a summary, or an explanation β€” and your content is locked behind a JavaScript wall β€” you simply don't exist in that answer. No ranking. No visibility. Nothing.

For a developer who shares ideas and builds presence, that's a problem I couldn't ignore.

Why Vite + React SPA Can't Solve This

The core issue is architectural. A Single Page Application works like this:

  1. Browser requests a page
  2. Server returns an empty HTML shell + a large JS bundle
  3. JavaScript executes and renders the actual content

An AI crawler or any HTTP client that doesn't run JavaScript stops at step 2. They get the shell. The content never arrives.

You can patch around it β€” I did, with prerendering. And prerendering helps for simple cases. But once your app has complex state, dynamic i18n, context providers, and client-side routing, prerendering becomes a constant battle: missing routes, hydration mismatches, trailing slash edge cases that swallow entire language directories.

I spent dozens of minutes debugging why /zh/ served empty HTML even though dist/zh/index.html existed and was correct. Cloudflare Pages was stripping the trailing slash, falling back to the root shell, and serving nothing. That's the kind of invisible failure that client-side rendering creates.

The Switch to Astro

I migrated leonkang.com to Astro.

The pitch is simple: Astro generates real HTML by default. When a crawler β€” AI or otherwise β€” fetches /en/blog, it gets actual content. Article titles, summaries, tags, dates. Everything readable, no JavaScript required.

What I needed from the migration:

  • Multi-language support (/en/, /zh/, /ja/ URL routing) β€” Astro has this built in
  • Static output for AI and crawler readability β€” Astro's default
  • React components where needed β€” Astro Islands let me keep interactive components in React with a client:load directive
  • Cloudflare Pages deployment β€” zero config with the official adapter

The migration wasn't without friction. Routing patterns change. The mental model shifts from "one SPA with client-side navigation" to "real pages with optional client-side hydration." But the result is exactly what I needed: every page is a real HTML document with real content.

Now when something fetches /en/blog, it gets seven blog posts, their titles, their summaries, their tags. Readable. Indexed. Present.

Technology Exists to Serve People and Content

There's a tendency in this industry to treat technology choices as identity. "I'm a React developer." "I use Vite for everything." "Why would I need anything else?"

I get it. Familiarity is genuinely valuable. Switching costs are real.

But I think the more honest framing is: technology is infrastructure for content and people. When the infrastructure stops serving the content β€” when what you've written becomes inaccessible to the channels people actually use β€” it's time to change the infrastructure.

Vite + React SPA was the right choice when I built the site. It isn't the right choice now, given how I want my content to travel.

Astro is right for this moment. Something else might be right for the next one. That's not instability β€” that's the job.

The web keeps changing. The way people find things keeps changing. A personal site that was "good enough" two years ago might be actively working against you today.

I'd rather rebuild than disappear.


This site is built with Astro, deployed on Cloudflare Pages. All pages are statically generated with full i18n support across English, Chinese, and Japanese.