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!
Here’s the example repo and the little Parcel plugin which makes it possible.
The post introduces the concept of RSC from server loaders:
export async function loader({ params }) {
let { contentBlocks, ...product } = await getProduct(params.productId);
return {
product,
content: (
<div>
{contentBlocks.map((block) => {
switch (block.type) {
case "image":
return <ImageBlock {...block} />;
case "gallery":
return <GalleryBlock {...block} />;
case "video":
return <VideoBlock {...block} />;
case "text":
return <TextBlock {...block} />;
case "markdown":
return <MarkdownBlock {...block} />;
default:
throw new Error(`Unknown block type: ${block.type}`);
}
})}
</div>
),
};
}
export default function Article({ loaderData }) {
return (
<ProductLayout product={loaderData.product}>
{loaderData.content}
</ProductLayout>
);
}
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 app
let context = new AsyncLocalStorage<ReturnType<typeof createLoaders>>();
// React Router middleware to provide the context to the app
export const dataMiddleware: MiddlewareFunction<Response> = async (_, next) => {
// create batchFunctions for just this request
let batchFunctions = {
movie: batch(batchMovies),
actor: batch(batchActors),
};
return new Promise((resolve) => {
context.run(batchFunctions, () => {
resolve(next());
});
});
};
// load function to be used anywhere, especially in components
export function load() {
return context.getStore() as ReturnType<typeof createLoaders>;
}
Ryan is looking to bring this kind of concept into React Router.
Leave a Reply