Server Components are Cool! Frameworks may or may not be.
I, along with many ReactJS devs, have been following the development of the "new" React Server Components API with excitement. It solves some common problems in React around data fetching and efficiency in client side applications. If you're interested in learning more about the API I'd recommend you listen to the recent JS Party podcast with Dan Abramov and Joe Savona from the React Team on the future of React, and then check out the React Server Components Demo on GitHub.
One aspect of the planned Server Components API that I personally dislike is the reasoning from the core team that in order to make use of them, you should utilize a framework like Next or Remix. If you're already using one of these, then great! You will get this feature in time. But, if you're like me and would rather assemble right size tools on your own, or you have a large application you'd rather not completely refactor, this leaves something to be desired. I want there to be a way to use Server Components without a framework.
With this in mind, I've started building a compiler of sorts on top of TS-Morph that will allow you to write your client and server components together, and split them into two bundles automatically for deployment to your server of choice and client application. Ideally, this would work with both Typescript and JavaScript codebases. So far it does, but as I get deeper I can't make too many promises on this feature.
A tool for creating Server Components without a Framework
The emphasis of this tool would be to minimize both code and configuration, while introducing the least new dependencies into a code base. This starts with how you write your components. While the plan in Next, for example, is for developers to identify server and client components explicitly, their documentation points to a straightforward set of rules for how to divvy them up:
What do you need to do? | Server Component | Client Component |
---|---|---|
Fetch data. | ✅ | ⚠️ |
Access backend resources (directly) | ✅ | ❌ |
Keep sensitive information on the server (access tokens, API keys, etc) | ✅ | ❌ |
Keep large dependencies on the server / Reduce client-side JavaScript | ✅ | ❌ |
Add interactivity and event listeners (onClick(), onChange(), etc) | ❌ | ✅ |
Use State and Lifecycle Effects (useState(), useReducer(), useEffect(), etc) | ❌ | ✅ |
Use browser-only APIs | ❌ | ✅ |
Use custom hooks that depend on state, effects, or browser-only APIs | ❌ | ✅ |
Use React Class components | ❌ | ✅ |
With these rules as a guide, it should be possible to separate server and client components into categories automatically based on their dependencies. In fact, I've already completed some of this work which you can check out on GitHub. The remainder of the work is more testing and implementation around third party dependencies, then creating and compiling the server and client bundles.
This would be exposed as a command line tool, as well as a Node API, to allow developers to integrate this optimization step into their build processes without adding additional dependencies outside of the compiler, some types if you're not using Typescript already, and some new React core packages for the client and server coordination.
What's "Next" and how you can help
At the very least, this would provide a way for all React devs to try out server components without the overhead of learning and implementing applications in a heavy framework. At the very best, it would allow application developers to integrate server components in a lightweight and seamless fashion into new and existing codebases. Overall I'm excited about the possibilities. Are you?
If so, I'd love ideas and contributions! I'd be happy to chat about:
- Would you use this tool?
- If so, or if not, what would make it a better fit?
- What might you do to contribute to this open source project?
Let me know in the comments, I'd love to chat and work with y'all!
Top comments (9)
This is a great idea.
I've been working on something for React Native (mobile and web) with unified routing via React Router (including v6.4+ loaders, eliminating the need for get[Whatever]props) and filesystem-based routing via a Vite plugin (generating a routes file so mobile can use it too).
Essentially, a mini-framework of pick-and-choose components, letting Expo do what it does best (Android/iOS with easy DX), while dumping Expo's (CSR-only, or convoluted Next monorepo) Webpack setup to leverage the superior web DX of Vite for CSR, server components (SSR or SSG) and even desktop apps with Tauri or Electron.
I hadn't even thought about generating separate bundles for server and client. I'd love to discuss further. Feel free to DM me.
Yeah, its interesting that I don't hear the React Core Team talking about this use case either. I suppose it has a dependency on Typescript to do the static analysis which isn't their focus, but I wonder if there are other issues in my blind spot that they may have considered. We'll see as I continue! It's been suggested that I file an issue somewhere appropriate on GitHub to put it on their radar and get feedback. I think I'll do that
This is a great idea.
I am getting the feeling that with Next & Remix the true spirit of React.js which was one can just create JavaScript components that would run anywhere with ease is gone.
Its more about frameworks around React that are dictating what to do now.
I also am not a fan of labeling components as server or client, a runtime should look at the written code and trans-pile it to either server or client depending on where it can run.
With alot of newer meta frameworks that are now doing this stuff out of the box like qwik-city & solid-start is also great, however I am worried if in future I should put all my eggs in one basket & learn one framework which may or may not be flavor of the month & will it get enough traction for a Eco-system.
To be fair, Next and Remix have a pretty strong foothold in the space as well as commercial enterprises backing them, so I imagine barring a big shift in the space that they're going to be actively developed for some time. I do think there's always room for tooling that sidesteps them though, and low configuration tooling is the preference for many reasons. I'll update with another post when this one is ready for testing, so stay tuned!
Rather than using an existing framework like next, you prefer the hard way😅👍
It could be the harder way, it could be the easier way. It depends on the nail as to which hammer you use. Next is not the easiest solution to every problem
I totally agree with you here.
Treating Next as bible is a narrow way of thinking.
With JS fatigue & new frameworks every month there is more chance of divergence in the front-end framework space.
The future for generic component technology will be more favorable for developer experience.
Treating any one tool as the "one" tool, or any solution as the only solution denies the vast nature of the space in which we encounter problems and search for solutions. Also, even if you're not planning on building with framework agnostic tools, using such tools for testing or to prove a hypothesis will always be a valid use case as well. While I also think frameworks provide a favorable developer experience, they're again not the only tool that should ever be used for any problem.
You had me at ts-morph :)