There are two ways to ship a single page app with React Router
Server rendering is enabled by default. Set the ssr flag to false in react-router.config.ts
to disable it.
import { type Config } from "@react-router/dev/config";
export default {
ssr: false,
} satisfies Config;
With this set to false, the server build will no longer be generated.
With server rendering disabled, you can still use clientLoader
and clientAction
to manage route data and mutations.
import { Route } from "./+types/some-route";
export async function clientLoader({
params,
}: Route.ClientLoaderArgs) {
let data = await fetch(`/some/api/stuff/${params.id}`);
return data;
}
export async function clientAction({
request,
}: Route.ClientActionArgs) {
let formData = await request.formData();
return await processPayment(formData);
}
Pre-rendering can be configured for paths with static data known at build time for faster initial page loads. Refer to Pre-rendering to set it up.
After running react-router build
, deploy the build/client
directory to whatever static host you prefer.
Common to deploying any SPA, you'll need to configure your host to direct all URLs to the index.html
of the client build. Some hosts do this by default, but others don't. As an example, a host may support a _redirects
file to do this:
/* /index.html 200
If you're getting 404s at valid routes for your app, it's likely you need to configure your host.
Typical Single Pages apps send a mostly blank index.html template with little more than an empty <div id="root"></div>
.
In contrast react-router build
(with server rendering disabled) pre-renders your root and index routes. This means you can:
React Router will still server render your index route to generate that index.html
file. This is why your project still needs a dependency on @react-router/node
and your routes need to be SSR-safe. That means you can't call window
or other browser-only APIs during the initial render, even when server rendering is disabled.