When using React Router's framework features, your application is automatically code split to improve the performance of initial load times when users visit your application.
Consider this simple route config:
import { type RouteConfig, route, } from "@react-router/dev/routes"; export default [ route("/contact", "./contact.tsx"), route("/about", "./about.tsx"), ] satisfies RouteConfig;
Instead of bundling all routes into a single giant build, the modules referenced (contact.tsx
and about.tsx
) become entry points to the bundler.
Because these entry points are coupled to URL segments, React Router knows just from a URL which bundles are needed in the browser, and more importantly, which are not.
If the user visits "/about"
then the bundles for about.tsx
will be loaded but not contact.tsx
. This ensures drastically reduces the JavaScript footprint for initial page loads and speeds up your application.
Any server-only Route Module APIs will be removed from the bundles. Consider this route module:
export async function loader() { return { message: "hello" }; } export async function action() { console.log(Date.now()); return { ok: true }; } export async function headers() { return { "Cache-Control": "max-age=300" }; } export default function Component({ loaderData }) { return <div>{loaderData.message}</div>; }
After building for the browser, only the Component
will still be in the bundle, so you can use server-only code in the other module exports.