Build your own Full-Stack framework

Feeling the web developer fatigue? You are not alone!

The state of the Web ecosystem in 2024

Over the last 3 to 4 years, we've witnessed an explosion in the number of frontend and full-stack frameworks and libraries. This boom has added significant variety to an already diverse ecosystem, introducing technologies like Solid, Svelte, Qwik, Astro, Remix, Vite, Lume, HonoX, Tailwind CSS, Panda CSS, StyleX, and Shadcn UI, among others.

In addition to libraries and frameworks, we've seen the emergence of new and impressively fast JavaScript runtimes, such as Deno, Bun, and WinterJS.

Serverless computing and edge development have also surged in popularity, particularly within the JavaScript community. Platforms like AWS, CloudFlare, and Vercel offer runtime environments specifically tailored to these paradigms, including AWS Lambda with Node, CloudFlare Workers & Pages, and Vercel's Edge Runtime.

In frontend development, we've observed a revival of old paradigms, such as SSG (Static Site Generation), SSR (Server-Side Rendering), and more recently, RSC (React Server Components) and HTML streaming. While some of these concepts aren't new to other programming languages like PHP, they represent fresh approaches within the JavaScript ecosystem.

Another technology that has significantly impacted the industry is Generative AI, influencing the adoption of new technologies (especially HTML streaming) and shaping new paradigms and patterns for developers to learn and adopt.

Given the rapid introduction of these technologies, it's understandable that many of us experience information fatigue. The list of concepts to grasp is extensive, and technology evolves faster than our ability to integrate it sustainably. The new code you write today may well become obsolete in 5 years or less!

Next.js: A sweet and convenient trap

Here's the lowdown on Next.js from a dev's perspective. We're in a golden era of web development, with more tools and frameworks at our disposal than ever before. In this sea of innovation, Next.js stands out, especially for those of us knee-deep in React. It's packed with features that make you want to dive right in. But, it's not all sunshine and rainbows.

The catch with Next.js? It's a bit too cozy with Vercel. Sure, Vercel's free plan is great for starters, but once your project picks up steam, the costs can sneak up on you. As a React developer, I appreciate everything Next.js offers, but the moment you try to step outside the Vercel ecosystem, you hit a wall. It feels like you're boxed in, specially when features like image optimization don't work as good as it does in Vercel, or are simply not supported.

I get it, Vercel is a business and they need to make profit, and they have open sourced the Build Output API, which is a step in the right direction, but the feeling of being locked in doesn't go away. Whenever a big update drops, you're left wondering how it'll affect your project if you're not fully on board with Vercel.

There's some hope with SST and OpenStack working to offer more flexibility, but it's not perfect. Hosting Next.js yourself, say with Docker, means missing out on some features and optimizations (e.g. caching of optimized images).

Then there's the dev server debate. Next.js comes with its own, but Vite is taking the developer world by storm by being adopted in every other major framework and tool. Vite is fast, flexible, and its plugin system is very good. It's hard not to envy Vite users when you're looking for a streamlined and efficient development environment. Parcel is also worth mentioning, looking awesome and all-batteries included since version 2.

In a nutshell, Next.js is great if you're all in with Vercel, but the moment you want more freedom, you start feeling the constraints. It's a bit like being given the best tools for a job but only being allowed to use them in one specific room. We're all searching for that perfect balance of features, flexibility, and freedom. For now, Next.js is a compelling option, but with a few strings attached.

What If I want to deploy certain serverless functions to AWS and others to CloudFlare? Not possible with Next.js alone, you need to integrate CDK or Wrangler in your project and make REST API calls from your Next.js project, making Server Actions pointless.

Other frameworks

Other frameworks like Remix and Astro are cool, but they don't offer all features Next.js has.

Astro, for instance, is more focused on offering Static Site Generation rather than dynamic and interactive (although it is still possible).

Remix announced they are studying the possibility to support RSC, but I don't expect it any time soon (probably after React 19 becomes stable).

I personally love React Server Components and the files & layout system of the App Router, but unfortunately I didn't find other frameworks offering something similar yet.

Remix and Astro are projects to follow closely. They have a great developer experience and a good freedom/democracy when it comes to platform interoperability / exportability. Things may get interesting during this and the next year.

The State of React: just why??

The React team recently announced the upcoming changes that we can expect for React 19.0.

There hasn't been any new React release since Summer 2021, everything has been cooked internally as canary releases that have been adopted by "stable" Next.js releases (sold as production-ready 👀): specially React Server Components and Server Actions.

I am not very happy with these (kind of opaque) decisions. Communication and documentation has been poor in the last years, to the point that the community didn't know at the beginning if RSC & Server Actions were part of React or only specific to Next.js.

I've been also considering changing to Vue, Solid or Svelte, even Astro, but professionally I am still using React every day, so It wouldn't make sense for me to do the switch, I would just consider any of them for small experimental side projects.

The fatigue I talked about in the intro is real, and changing to a new framework wouldn't be productive for me. At the end all you want is to ship great things rather than spending most of your time worrying about the technology: researching, learning, prototyping and then start over again because it didn't work as expected. Learning and research is also part of our job as developers, it is also important, but it becomes problem when it affects our productivity.

All I hope is that, from React 19 on, things start to get easier and more clear for us, and the React team goes back to a normal pace of release cycles.

Build your own framework

So, after all that's been said and done, you might be feeling like stepping off this wild ride and starting fresh. Why not build your own framework? Just the essentials, nothing more, nothing less.

Honestly, there's never been a better time to do it. As web developers, we've got more resources, tools, and community support than ever before. And it looks like it's only going to get easier from here.

If there's something I miss from my PHP days is having a composable framework like Symfony, the PHP framework. You can adopt Symfony entirely as your only framework or just use some of its components as dependency. You can also build another framework on top of Symfony components, like Laravel did. We should have something similar for full-stack web development in TS/JS.

The thing is, we've been missing the right set of tools to truly go head-to-head with something as feature-rich as Next.js, especially when it comes to stuff like RSC support.

Projects and initiatives like Vike and Vinxi (both powered by Vite) are making efforts in that sense, even though they're still in the early stages. I specially like Vinxi: it offers full freedom in terms of routing (you can decide how to organize your files and which router library to use) and it recently added support for RSC with its own implementation (very similar to Next.js's). Vike felt more restrictive.

What I don't like from both is their documentation and how complex is to understand what their code is doing. I'd rather have a paper / documentation / example-first approach for projects like thes, rather than code-first.

First define your target architecture, how should it work, document it, then implement it. Iterate.

The idea behind "build your own framework" is to exactly no depend on other frameworks, and to not be forced to the ways and conventions of specific libraries.

PizzaJS 🍕

So here comes my concept, how my ideal framework should be, my journey to shape and bring to life the "Symfony" counterpart of the JavaScript/TS world.

For some months I've been in a research phase, and I even got a name!

I named it PizzaJS, because everyone loves Pizza. The funny part is that I want Pizza's different pieces to be named after the ingredients of a pizza: Basil, Mozzarella, Pomodoro, like the colors of the italian flag 🇮🇹 as well.

I am taking inspiration from Symfony, Next.js, Vike, Vinxi and also Hono/HonoX (and will probably using parts of them as well).

The Pizza Philosophy

  1. Documentation-first: First the concept and theory, then the code. PizzaJS will first have the documented theory of how it should work, backed by coded proofs of concepts.

  2. Universal and Interoperable: It should be compatible with all major JS runtimes and cloud services: Node, Deno, Bun, Winter, Edge, etc.

  3. Modular, Composable and Pluggable: Developers should be able to decide to integrate all components or just some of them. They should also be able to replace any component with their own custom implementation.

  4. Unopinionated: Components shouldn't be tightly coupled to each other (e.g. the server component shouldn't directly depend on the router one). Developers should have the freedom to replace one component with another library / implementation.

  5. Familiar: It should feel familiar to use the framework or some of its components. Don't reinvent the wheel. Use (and respect) Web standards and community conventions as much as possible. Build on top of Vite as well.

  6. Extensible: The framework should support extensibility via a Vite-compatible plugin API. It should also be able to pass configuration to Vite. Initially with a React flavor only, but the components should be agnostic enough to bring other frameworks to the pizza party.

  7. No surprises: I take the principle of least surprise/astonishment very seriously. No surprises, no magic or black boxes. No side-effects or pollution of native APIs (like redefining how fetch works). Again, respect web standards and how they are intended to work.

  8. Declarative: Explicit and declarative rather than of by convention. Devs should know what their code is doing all the time, and where/how it will be executed.

  9. Multimodal: SPAs, MPAs, PWAs, SSG, SSR, RSC, HTML Streaming... all should be eventually supported in a declarative way.

  10. Performant and Compact: I'd rather have a minimal set of dependencies, small bundle size, and well tested code that is able to scale, backed by data and benchmarks.

It is a very ambitious project that I have a lot of uncertainties about, but the journey it's what matters. For sure I will learn a lot about JS framework internals, runtimes, etc., things I wouldn't learn much about if I stayed in my comfort zone as a full stack dev.

I want (or will try) to document my journey about going framework-free in this blog. I will be talking about both JS and CSS frameworks/libs, and probably about new promising HTML technologies as well.

Stay tuned here and on https://github.com/pizzajsdev

Did you find this article valuable?

Support Javier Aguilar by becoming a sponsor. Any amount is appreciated!