DEV Community

Cover image for Iam 12 .I Built an AI Web App in a Single 92KB HTML File. No React. No Build Step. No Excuses.
Harun - solo dev
Harun - solo dev

Posted on

Iam 12 .I Built an AI Web App in a Single 92KB HTML File. No React. No Build Step. No Excuses.

most ai apps ship a 4MB javascript bundle.

they need node 22. they need webpack. they need a $40/month vercel plan. they need a macbook to run the dev server without the fan sounding like a jet engine.

i don't have any of that.

i have a $150 poco c55 phone. i have cloudflare's free tier. i have a single index.html file.

and i built a full ai coding mentor that streams responses, reads images, exports conversations, handles auth, and enforces an 11-article constitutional safety framework.

the entire frontend is 92 kilobytes.

here's how.

the stack (and why it's boring on purpose)

layer tool cost
frontend single index.html (vanilla js + css) $0
hosting netlify (static) $0
backend logic cloudflare worker $0
database/auth supabase $0
llm groq (free tier) $0
web search tavily $0

total monthly cost: zero dollars.
total npm dependencies: zero.
total build tools: zero.

i don't run npm install. i don't run npm run build. i edit a file. i hit deploy. it's live in 8 seconds.

why no framework?

because i'm coding on a phone.

react needs a dev server. vue needs a bundler. svelte needs a compiler. all of them need a terminal that my $150 phone can't run smoothly.

vanilla js runs everywhere. it runs in the browser i already have. it doesn't need a node process eating 400mb of ram on a device with 4gb total.

and here's the secret: for an app this size (~1,900 lines of js), you don't need reactivity. you need two functions:

  1. renderMessages() — redraws the chat
  2. renderConversationList() — redraws the sidebar

when state changes, i call the function. that's it. no virtual dom. no reconciliation. no hydration. just innerHTML and move on.

the 92kb breakdown

inside the single index.html:

  • ~500 lines of css (design tokens, dark/light themes, print stylesheet, responsive breakpoints)
  • ~200 lines of static html (app shell, modals, sidebar)
  • ~1,400 lines of vanilla js (state management, supabase auth, streaming fetch, markdown renderer, export system, pinning, image compression, voice input)

no external css files. no external js files. no font imports. no icon libraries. every svg icon is an inline path string in a js object.

the browser downloads one file. it parses it. the app runs. done.

streaming without libraries

most people reach for socket.io or some sse client library.

i use fetch() with a readablestream reader:

const reader = res.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = new TextDecoder().decode(value);
// parse sse lines, append deltas to bubble
}

that's it. that's the whole streaming system. no library. no abstraction. just the platform.

the constitutional core (server-side)

the real intelligence isn't in the frontend. it's in the cloudflare worker.

every request passes through an 11-article constitution before it hits the llm. the worker:

  1. checks if the prompt is toxic (even if encoded in morse code or base64)
  2. picks the right model chain based on the task
  3. injects the constitutional system prompt
  4. optionally runs a tavily web search
  5. streams the response back with source citations

the frontend is dumb on purpose. it renders whatever the worker sends. the worker is the brain. the html is the face.

what i learned

  1. constraints are the best architect. if you can't install npm packages, you stop reaching for them. you start reading mdn instead.

  2. boring tech ships faster. while my classmates were configuring vite aliases and debugging tailwind plugins, i was already talking to users.

  3. the platform is enough. fetch, localstorage, blobs, url.createobjecturl, window.print, navigator.clipboard — these are all native. you don't need a library for any of them.

  4. senior devs respect constraints. when i told a netflix engineer my whole app loads in under 1 second on 3g, he didn't laugh. he nodded. because he knows that's harder than shipping a 4mb bundle on a fiber connection.

try it

koda-aicodementor.netlify.app

open it on your phone. open it on a 5-year-old device. open it on a hotel wifi that barely works. it loads. it streams. it teaches.

92 kilobytes. zero dependencies. zero excuses.

Top comments (1)

Collapse
 
svgicons profile image
Svg/icons •

Do you normalize those inline icons to one viewBox and currentColor? That small convention makes a path-string registry much easier to size and theme consistently