My story creating a new React meta-framework
Tags: react, vite, rsc
Published: 2024-06-10 22:20:51

I have a great idea for a new hobby project! As I am a React developer, I'll use it again for implementing this project, that's an easy choice. I use Next.js at work. It's fine, but there are some pain points in using it, so I don't want to go with it for my own project. I struggle with it during work, so why should I struggle in my spare time. I want to have some fun!

I love Vite! When I used Vite for a React SPA app, with React Router and react-query, I liked it a lot! It was blazing-fast! No need to wait for any Webpack bundling, just using ES modules, it was heavenly. I started to use Vite when I started experimenting with streaming server-side rendering using React Suspense. I also created a micro-frontend system based on Vite and a self-hosted fork of esm.sh instead of Module Federation, but that's another story.

But this Vite setup I had for an SPA didn't work for server-side rendering as I wanted it to. Should I use Remix then? Remix now supports Vite! Though choice. I like some parts of Next.js since Next.js 13. More precisely, I like the new React server-side rendering features a lot. React Server Components are awesome! To have complete control over the React hydration and which parts of the rendering is server vs client is great. Using server actions with Next.js is also fantastic! I like how much this new way is close to traditional web development. I like that links and forms are driving navigation, mutation and that state management is shared between the client and the server using standard solutions, like search params and RESTish routing, even some cookies if needed. Web development is again so much easier and fun this way. But I don't want to have all the caching problems of Next.js. I don't want bundles and waiting. So what should I use again? Remix is not supporting these. What about Astro? I like Astro, I would possibly use it for a more content driven project, but this time, it's not my best choice. I only want to use pure React. I heard there's a new minimal React framework, Waku. I want to have even less setup than that!

To summarize, what will I need or want to use for this project?

- Vite
- server-side rendering
- React Server Components
- client components
- server actions
- full access to the HTTP context
- a minimal setup, no boilerplate
- fast dev server, build and deploy

Is there a framework like that? No. I worked on some libraries and frameworks in the past, like JayData or odata-v4-server, so if I would create a new React framework with the requirements I have, how should it be done? That's a though question as there's no documentation for these React features yet, just some tests in the React repo and while Next.js is open source, the codebase is huge! I love to experiment with un-documented tech, I loved when I learned the intricacies of the unknown and then tweaking it to the max to create an awesome, jaw-dropping experience, like porting Wolfenstein 3D to the web from scratch, directly porting some C/C++ code to JavaScript while learning a lot or using WebAssembly to create a DOOM web runtime environment to play any WAD files from DOOM I or II, even other DOOM-engine games like Heretic. I loved re-engineering these retro games to make them playable in the browser or on my phone or tablet. I also started to make a dive and started messing around with the Elder Scrolls series to remake it in the browser! It was so much fun! So, without any hesitance, I started to create some proof of concepts.

RSC is easy. You just need to call `renderToReadableStream` and send it to the browser. But what about hydration and client components? Now that's a challenge! You need to render your React tree to the RSC payload in a thread with "react-server" module resolution conditions. This payload will include all the static HTML nodes and references to client components and server actions. To render client components properly, you need to have a snapshot. That's the RSC payload, with the static HTML nodes. Then, you need to get a new React tree from this. To get that, you need to use `createFromReadbaleStream` to transform your RSC stream to a React tree, then use a different type of `renderToReadableStream`, but this time not using the *react-server-dom-webpack* package, but *react-dom*. While doing this, you need to send your RSC payload in parallel with the HTML content to hydrate your React application on the client as you stream the server-side rendered content. You also need to have all the references ready to tag client components with the `react.client.reference` symbol and if you also want server actions, then with the `react.server.reference` symbol. So you need to transform your files differently for multiple environments during rendering and you also need to manage all the module resolution for these. Take this with all the workarounds you need to do to make this work with Vite. So after creating some Vite transform plugins and dealing with the complex rendering (not just a simple `renderToString` like in the old days), you're good to go, right?

A framework is much more, than making some proof of concept work. It's much more, than achieving something in a sandbox. It's very similar to game development or it's very similar to me, to my own game development experience as I always worked on some rendering engine for games and not as a game designer or creating content for a new game (with some tiny exceptions). After you finish with the gameplay, you need to start building all the other parts, like menus, configuration management, etc. A framework is not just a rendering engine and some core functionality. It has to provide some great developer experience. I had this partially because of Vite. If I would not have Vite, my job would have been much harder. But I had an idea. A vision.

When I experienced node.js the first time, I was amazed. I already worked as a frontend engineer, so node.js for me was a gate to another world, to another dimension. I was able to use all my expertise with JavaScript on the backend. I worked a little bit at this point with other backend solutions, like PHP or ASP.NET. But despite it's quirks, I loved JavaScript (I know, I know...). So node.js was the best thing to continue with. What made node.js awesome? `node server.js`. If you had a JavaScript file with any size, be it a tiny script or a large backend for a complex architecture, in the end it's just running a simple `node` command to start your server.

`react-server ./App.jsx`. I wanted to have this. So badly! All the frameworks are handling your entrypoint differently. Next.js is enforcing it's own file-based routing. It's so much more opinionated compared to React. Remix has a long setup to follow. I just wanted an `App.jsx` and a CLI tool to run it as my entrypoint, taking away all the project setup work that every project needs at the start.

I imagined this "Get started" (I also love *pnpm* btw):

```
pnpm add @lazarv/react-server
pnpm exec react-server ./App.jsx
```

No need for anything else. Simple as that. Not even a configuration file. Not even installing React directly! Just running the Vite development server, like I would do it for an SPA using `npx vite` with an `index.html` in place. I was amazed by a Vite demo Evan You did more than 2 years ago. It was minimal. It was elegant. It was awesome! I wanted to have the simplicity of node.js and Vite, just for React.

I also have to mention a very important presentation. It changed how I look on RSCs and the new way of React server-side rendering. It was Dan Abramov’s RemixConf 2023 presentation titled: “React from Another Dimension”. If you haven’t watched it yet, do it. RSC clicked for me watching it! Also the title was great as I listen to Liquid Tension Experiment a lot! :) 

My hobby project grew out of it’s cooking pot. Maybe it’s some sort of megalomania. But I always lose some scope as I dream big. In all my works, I have a much larger target in the end than at the start of that project. But if I’m committed to that project, I will finish and achieve my vision no matter what.

If you share the same view on frameworks like me, you can get my experience. Just head over to https://github.com/lazarv/react-server and give as much feedback as possible. I also sort of completed my hobby project. But not the original one. I used my own framework to create the documentation site for it. Check it out at https://react-server.dev. I hope you will also have fun trying it out!