RSC is mindbending, I won’t lie. Sometimes you have to think inside-out. But personally, I think RSC is awesome. The tooling is still evolving but I’m excited for its future. I hope to see more technologies thoughtfully blending the boundaries.
Ryan Florence introduces Jacob Ebey’s latest work to bring RSC to React Router.
We’re leveraging Parcel’s RSC support to help us figure out what React Router looks like when RSC is a first-class bundler feature. You’ll note in the preview template there’s a little Parcel plugin for routes.ts to button it all up and it’s pretty small. The effort to port to other RSC-native bundlers in the future should be equally minimal.
By targeting RSC-native bundlers like Parcel, we’re also helping to guide the direction of Vite’s official RSC support. Hiroshi Ogawa is currently working publicly on Vite RSC support and using React Router’s RSC APIs in Vite to validate their approach. By sharing our early RSC work publicly, we can help ensure that we’ll be ready once Vite RSC support finally lands.
This is very exciting for us: both React’s and React Router’s full feature sets will soon be usable with very little effort with any bundler, any JavaScript runtime, and any server!
There’s also a great section on batching and caching:
A couple major concerns with the RSC architecture are N+1 queries and over-fetching. Both are very easy to do when components can fetch their own data. We saw it happen in many Hydrogen v1 apps and it tanked performance to unacceptable levels.
If you’re not familiar, the first version of Hydrogen used RSC before abandoning it. Ryan proposes a new generic concept for solving this problem using batch-loader:
import{batch}from"@ryanflorence/batch-loader";// Async context to load data from anywhere in the appletcontext=newAsyncLocalStorage<ReturnType<typeofcreateLoaders>>();// React Router middleware to provide the context to the appexportconstdataMiddleware: MiddlewareFunction<Response>=async(_,next)=>{// create batchFunctions for just this requestletbatchFunctions={movie:batch(batchMovies),actor:batch(batchActors),};returnnewPromise((resolve)=>{context.run(batchFunctions,()=>{resolve(next());});});};// load function to be used anywhere, especially in componentsexportfunctionload(){returncontext.getStore() as ReturnType<typeofcreateLoaders>;}
Ryan is looking to bring this kind of concept into React Router.
Atomic CSS is a great idea. You can keep CSS size growth sub-linear in large applications with a lot of components.
Co-locating styles with React components is a great idea too. You can keep the styles you need right next to the component.
Many folks implement these ideas with Tailwind.
It’s fine if you like Tailwind. But Tailwind is not CSS — it’s a DSL of class names to apply styles. You need to learn Tailwind. Your designers need to learn it. Keeping your Tailwind DSL synced up with tools like Figma which exports CSS introduces friction and conversion.
And you’re going to need a larger monitor. Courtesy of @RhysSullivan, here’s a single div styled with Tailwind in IMAX 70mm:
Single div styled with Tailwind on IMAX 70mm. Image credit: @RhysSullivanVia X
Meta built StyleX to solve these problems. Yahoo Mail built a very similar system internally over 6 years ago where you write CSS as JavaScript objects co-located with your React components. Your CSS looks like CSS.
Yahoo Mail’s entire CSS was under 45 KB gzipped and it’s a huge application. It was so small we simply inlined it into the SSR HTML.
I hesitate to recommend StyleX for all projects. The ergonomics and open-source build tooling need refinement. Surely Meta has internal tools they use for building StyleX which are better than the open-source tools.
But the idea of StyleX is fantastic. I believe the public open-source implementation will get there eventually. The ideas are too good.
The most common error I see is to assume that shipping is easy. The default state of a project is to not ship: to be delayed indefinitely, cancelled, or to go out half-baked and burst into flames. Projects do not ship automatically once all the code has been written or all the Jira tickets closed. They ship because someone takes up the difficult and delicate job of shipping them.
[…]
In my experience, projects almost always ship because one single person makes them ship. To be clear, that person doesn’t write all the code or do all the work, and I’m not saying the project could ship without an entire team behind it. But it’s really important that one person on the project has an end-to-end understanding of the whole thing: how it hangs together technically, and what product or business purpose it serves.
From Genesis, man enters not a paradise without labor but a world of intentional creation. The LORD God places man in the Garden of Eden “to dress it and to keep it” (Genesis 2:15) establishing labor not as punishment but as sacred vocation. This original calling invites us to co-create the Kingdom, tending and developing the world with intention and care. Our fundamental purpose is not consumption but participation in the ongoing work of creation.
The serpent’s temptation represents the first shortcut in human history. “Ye shall be as gods” (Genesis 3:5) was not an invitation to deeper engagement with creation, but a way to get out of the work required to tend to it. The consequence wasn’t the introduction of work itself, but its corruption into burdensome toil: “In the sweat of thy face shalt thou eat bread” (Genesis 3:19). Humanity’s first sin was, in part, choosing the easy shortcut over the meaningful process – preferring effortless gain to the demanding but fulfilling work of tending the garden.
This first temptation remains alive today. Our post-enlightenment view that our world is purely material—that our lives are the outcome of physical processes devoid of feeling, craft, or meaning—is to discount the unique, historical, and stubbornly detailed nature of reality. This view misses what is evident: that the world we inhabit bears the marks of exacting, purposeful craftsmanship on both human and cosmic scales. Viewing the world as raw material is a cheap shortcut around the demanding, hermeneutic work of understanding the past and engaging deeply with the present.
The outputs of these shortcuts are Slop, the dominant cultural output of the twenty-first century. Slop emerges when we eliminate not just toil (the burdensome aspects of work) but labor itself (the meaningful human engagement with creation). Slop is production without history. Slop is detached from genuine human contribution. Slop born of effortless, replicable processes.
[…]
Language models provide the means for industrialization of Slop. In their highest calling, these tools can eliminate genuine toil: tending to burdensome emails, litigating with your co-op board, or drafting a parking ticket appeal. But when we ask a model to write a poem, design a church, or compose a eulogy, we get something fundamentally different from human creation. The model has never lost a loved one, never stood in a holy space, never lived. We can and should automate toil, but we must preserve craft.