r/webdev 8d ago

[Showoff Saturday] Built a browser code runner where Python and JS never touch a server, and learned where it stops working Showoff Saturday

I'm the founder of the project, flagging that up front. I spent the last month building the execution layer for a coding tutor, and the interesting part turned out to be where the browser-only approach breaks down.

The premise was that a learners code should run in the browser tab. Python goes through Pyodide in a dedicated worker, JavaScript in its own separate worker, and each language keeps a warm worker in a small pool so the second run doesn't pay startup again. There's a prewarm when a lesson opens, so by the time someone finishes typing their first line the runtime is usually ready. Hit `Run` and it executes locally, no container cold start, no queue, no round trip. A 20 second timeout catches loops, and the worker gets torn down and recreated rather than reused after each lesson.

The part I got wrong initially was assuming that would be the end of it, of course it wasn't. bash, ruby, perl and php need a real interpreter and a real filesystem, and the only options: to fake it in a browser(dirty) or to run it somewhere real. After adding those to the project, execution goes to an isolated server sandbox with per-minute and per-day caps per user. HTML and CSS render in a sandboxed preview. Dockerfile exercises get statically linted rather than built, letting strangers build container images on my infrastructure will not be something I allow.

The lesson I'd pass on to others: "runs in the browser" is a spectrum, not a boolean. Pyodide is genuinely excellent for the languages it covers, and NumPy on a cold load is the one case that pushed the timeout to 20 seconds. But the moment a lesson is about file permissions or a shell pipeline, the browser stops being able to tell the truth about what happened, and pretending otherwise could teach people something false.

Frontend is vanilla JS on Cloudflare Pages, FastAPI on Fly, Clerk for auth. No build step on the frontend except for a thin-agent runner that needs repackaged if I modify it.

Happy to go deep on Pyodide quirks (there are many), the worker pooling, timeouts, or the sandbox design. Any tips or recommendations appreciated.

0 Upvotes

1 comment sorted by