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.

7 min read • View on GitHub • More from aidenybai

A small personal website storefront sits in front, while a hidden workshop is attached to its side. A bundled file rolls from the side room into a cable that feeds the front door script tag. The image explains that the public page is only the shell, while the real work happens in the sidecar bundle.
The visible site is the front door. The interesting machinery lives in the workshop beside it.

Introducing Same.dev Clone any website with pixel perfect accuracy One-shots Nike, Apple TV, Minecraft, and more!

Aiden Bai, Author/Developer · Aiden Bai on LinkedIn
Key Takeaways

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.

A WSJ-style hedcut portrait of Aiden Bai. The image grounds the origin story in the builder behind the repo, while the simple white background keeps the focus on the technical teardown.

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.

The bundle moves from disk to browser without entering the app's normal module graph, which is why the loader can hot-swap it without a full reload.

// 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)
}, [])
A browser window in close-up with one script tag being pulled out and a fresh script tag sliding into its place. A small clock face set to one second suggests the polling loop, and a narrow conduit from an API route box delivers the updated bundle. The scene explains how the repo replaces scripts instead of doing a full page refresh.
This is not module HMR in the usual sense. It is a controlled script swap across a cache boundary.

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

PatternWhat updatesHow the browser gets itWhere it breaksBest use case
Standard personal sitePage content and local componentsNormal Next.js render cycleFine for pages, useless for outside bundlesBrochure sites and blogs
Fast RefreshEdited React modules inside the app graphTurbopack or React refresh pushes updates automaticallyCannot reach a separate artifact outside the graphApp code under one build system
Sidecar loader in this repoAn external bundle file pointed to by BUNDLE_PATHDev-only loader fetches /api/library and swaps the script tag when the text changesPolling is blunt, and the bundle must be script-safeTooling that lives beside the app
npm link or local package wiringPublished or symlinked package codePackage resolution and rebuildsLinking can be brittle and cache-heavyShared 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.