DEV Community

as nara
as nara

Posted on

The simplicity is complicated.

I’ve worked with React since the Create React App days—then moved on to Next.js, Remix, and later Vike.

Along the way, I picked up a lot of best practices to solve real-world company problems while still keeping a solid developer experience—things like SSR, CSR, hooks, state management, and atomic component design.

Then about a year ago, I got a project with very different constraints:

full server-side only
strictly using Express.js
single port setup

At first, I tried to keep React in the stack by using it just for the frontend instead of a traditional templating engine.

But then the requirement changed: “zero build” project.

Just:

npm start

…and it should run in production.

At that point, React was no longer viable. Even without TypeScript, it still requires a build step. Using CDN wasn’t an option either.

After a lot of research, experimenting, and even brainstorming with AI—trying different libraries and approaches—I ended up going with EJS + Alpine.js.

Fully server-driven.

No client-side rendering, no Redux or heavy state management, no complex routing layer on the frontend. And honestly, the best part: no CORS headaches and no hydration issues.

What surprised me is that most of what I used to do with React… I can still achieve with Alpine. Component modularity is handled cleanly through EJS includes.

And it got me thinking:

Are we sometimes just creating complexity for problems that were already solved?

Top comments (0)