Inside aidenybai/website-2025: The Personal Site That Runs a Sidecar Bundle
A tiny API route and a polling loader turn a plain Next.js site into a live host for an external script.

Introducing Same.dev Clone any website with pixel perfect accuracy One-shots Nike, Apple TV, Minecraft, and more!
- The repo is less a brochure than a host for a dev-only sidecar bundle that lives outside the normal app graph.
- A cache-bypassed API route and a polling client loader let the browser swap in a fresh script without a full page refresh.
- Aiden Bai's broader toolmaking makes the design feel deliberate, because the browser is treated as a programmable surface rather than a fixed boundary.
- The stack choices point to the same goal, faster iteration with fewer layers between source and screen.
Most personal sites are static surfaces. This one acts more like a rack with a front panel: the visible Next.js app is just the shell, while the interesting part is a dev-only pipeline that serves a separate bundle through /api/library and swaps it into the page without asking the normal app graph for permission.
The homepage is the decoy
That is why the homepage reads as simple on first pass. In app/api/library/route.ts, the server reads a file path from BUNDLE_PATH and returns the bundle with caching disabled. In components/library-loader.tsx, the client polls that endpoint once a second in development and replaces the script element when the contents change.
The repo is less a brochure than a host. It is a narrow, deliberate escape hatch for work that lives outside the site's normal React tree.
Why Aiden Bai builds this way
This matches the broader shape of Aiden Bai's work. The same builder behind tools like Same.dev and React Grab tends to design around the browser as a programmable surface, not just a place to display components. A personal site built this way is not decoration, it is infrastructure.
The quote is noisy, but the signal is clear. Bai is not building a classic portfolio site. He is building a lab where the site can host experiments that do not fit neatly inside the app's module boundary.
How the sidecar loader works
The mechanism is simple enough to sketch, which is part of the appeal. The server serves one file from outside the app, the client checks for changes on a timer, and the browser gets a brand new script tag when the bundle updates.
// app/api/library/route.ts
export async function GET() {
const bundle = await readFile(process.env.BUNDLE_PATH!, "utf8")
return new Response(bundle, {
headers: {
"Content-Type": "application/javascript; charset=utf-8",
"Cache-Control": "no-store",
},
})
}
// components/library-loader.tsx
useEffect(() => {
if (process.env.NODE_ENV !== "development") return
let current = ""
const tick = async () => {
const next = await fetch("/api/library", { cache: "no-store" }).then((r) => r.text())
if (next !== current) {
current = next
swapScriptTag(next)
}
}
tick()
const id = window.setInterval(tick, 1000)
return () => window.clearInterval(id)
}, [])
The important detail is the cache boundary. The API route responds with raw JavaScript and no-store so every fetch sees the latest bundle. The loader does not try to reconcile modules. It compares text, and when the bundle changes, it tears out the old script tag and injects a new one.
Why this beats normal linking and refresh loops
| Pattern | What updates | How the browser gets it | Where it breaks | Best use case |
|---|---|---|---|---|
| Standard personal site | Page content and local components | Normal Next.js render cycle | Fine for pages, useless for outside bundles | Brochure sites and blogs |
| Fast Refresh | Edited React modules inside the app graph | Turbopack or React refresh pushes updates automatically | Cannot reach a separate artifact outside the graph | App code under one build system |
| Sidecar loader in this repo | An external bundle file pointed to by BUNDLE_PATH | Dev-only loader fetches /api/library and swaps the script tag when the text changes | Polling is blunt, and the bundle must be script-safe | Tooling that lives beside the app |
| npm link or local package wiring | Published or symlinked package code | Package resolution and rebuilds | Linking can be brittle and cache-heavy | Shared libraries with a normal package boundary |
The advantage is not speed in the abstract. It is control over where the source of truth lives. This repo keeps the app shell stable and lets the sidecar artifact move independently, which is exactly what you want when the thing you are iterating on lives outside the site's own dependency tree.
The rest of the stack is a performance manifesto
The rest of the repo points in the same direction. Next.js 15, React 19, Tailwind 4's CSS-first configuration, Biome, and Turbopack all cut down the amount of glue standing between source and screen. The aesthetic is not novelty for its own sake. It is fewer moving parts, less config drift, and a shorter path from edit to feedback.
Even the styling stack says the same thing. Tailwind 4 moves theme setup into CSS, Biome replaces heavier formatter and linter layers, and Turbopack keeps the feedback loop tight. The site is not trying to look minimal. It is trying to stay easy to change.
What this repo says about personal sites now
The strongest personal sites now do one of two things: they tell a story, or they reveal a workflow. This one does both, but the workflow is the sharper signal. It shows a builder using a website as a live host for sidecar tools, not as a frozen showcase. That is the real lesson: frameworks are increasingly just shells for the systems you invent around them.