What You Lose to the Build Step

I rebuilt a landing page with an index.html and a <style> tag. I went in expecting a nostalgia trip. I came out with the most satisfying afternoon of building I’d had in a long time.

I spent the rest of the week trying to name why.

What I’d stopped noticing was the distance between wanting something on the page and seeing it there. In plain HTML that gap is small. Edit a margin, save, refresh, and the button sits two pixels to the left. In a modern stack the same change travels through a component prop, a state update, a re-render, a reconciliation, a hydration check. Each step is reasonable in isolation. Strung together, they move the button off the center of your attention and put the toolchain there instead.

That is the real cost. I had been paying it without noticing. By the time a change appeared on screen, I had often stopped thinking about the change and started thinking about the build.

The debugging was where the difference showed up. When something broke, the search space was tiny. The markup was what I wrote. The CSS was what I wrote. I opened devtools and the element on screen was the element in my file. There was no stale closure hiding behind a virtual DOM, no effect firing because a dependency I’d missed changed shape. Half the time the fix was just reading my own code out loud.

Performance wasn’t a goal and it arrived anyway. The page ships around 20 KB. Click a link and the next view is already there, because there is nothing to hydrate. I didn’t tune anything. I simply didn’t add the things that would have needed tuning.

This works because the problem is small. A landing page is a solved shape. I was one person with one goal and no teammates to coordinate.

What I gave up by going bare was real: no component reuse, no shared design system, no ergonomic way to add the next page. None of that mattered for a single page. The build step is the cost of coordination, and coordination is the cost of being more than one person with one page.

The moment an app has real state, real routing, or a second contributor, the bare stack stops being a joy and starts being a liability. I’m not telling anyone to throw out their framework.

But the experiment clarified something I’d been treating as the price of doing real work. The build step, the component library, the state manager — they exist to manage the distance between intent and rendered pixels. For the page in front of me that afternoon, the distance was the only thing they were adding.

The browser had been ready the whole time.

I had just stopped talking to it directly.