Skip to content

Commit 892468e

Browse files
committed
Update docs for spa/prerendering
1 parent abe8008 commit 892468e

File tree

4 files changed

+44
-15
lines changed

4 files changed

+44
-15
lines changed

docs/how-to/pre-rendering.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ title: Pre-Rendering
66

77
Pre-rendering allows you to render pages at build time instead of on a runtime server to speed up page loads for static content.
88

9-
In some cases, you'll serve these pages _alongside_ a runtime SSR server. If you wish to pre-render pages and deploy them _without_ a runtime SSR server, please see the [Pre-rendering with `ssr:false`](#Pre-rendering-with-ssrfalse) section below.
9+
In some cases, you'll serve these pages _alongside_ a runtime SSR server. If you wish to pre-render pages and deploy them _without_ a runtime SSR server, please see the [Pre-rendering with `ssr:false`](#pre-rendering-without-a-runtime-ssr-server) section below.
1010

11-
## Pre-rendering with ssr:true
11+
## Pre-rendering alongside a runtime SSR server
1212

1313
### Configuration
1414

@@ -82,7 +82,7 @@ Prerender: Generated build/client/blog/my-first-post/index.html
8282

8383
During development, pre-rendering doesn't save the rendered results to the public directory, this only happens for `react-router build`.
8484

85-
## Pre-rendering with `ssr:false`
85+
## Pre-rendering without a runtime SSR server
8686

8787
The above examples assume you are deploying a runtime server, but are pre-rendering some static pages in order to serve them faster and avoid hitting the server.
8888

@@ -99,7 +99,7 @@ export default {
9999

100100
If you specify `ssr:false` without a `prerender` config, React Router refers to that as [SPA Mode](./spa). In SPA Mode, we render a single HTML file that is capable of hydrating for _any_ of your application paths. It can do this because it only renders the `root` route into the HTML file and then determines which child routes to load based on the browser URL during hydration. This means you can use a `loader` on the root route, but not on any other routes because we don't know which routes to load until hydration in the browser.
101101

102-
If you want to pre-render paths with `ssr:false`, those matched routes _can_ have loaders because we'll pre-render all of the matched routes for those paths, not just the root. Usually, with `prerender:true`, you'll be pre-rendering all of your application routes into a full SSG setup.
102+
If you want to pre-render paths with `ssr:false`, those matched routes _can_ have loaders because we'll pre-render all of the matched routes for those paths, not just the root. You cannot include `actions` or `headers` functions in any routes when `ssr:false` is set because there will be no runtime server to run them on.
103103

104104
### Pre-rendering with a SPA Fallback
105105

@@ -126,10 +126,12 @@ export default {
126126
} satisfies Config;
127127
```
128128

129-
You can configure your deployment server to serve this file for any path that otherwise would 404.
130-
131-
Here's an example of how you can do this with the [`sirv-cli`](https://www.npmjs.com/package/sirv-cli#user-content-single-page-applications) tool:
129+
You can configure your deployment server to serve this file for any path that otherwise would 404. Here's an example of how you can do this with the [`sirv-cli`](https://www.npmjs.com/package/sirv-cli#user-content-single-page-applications) tool:
132130

133131
```sh
132+
# If you did not pre-render the `/` route
133+
sirv-cli build/client --single index.html
134+
135+
# If you pre-rendered the `/` route
134136
sirv-cli build/client --single __spa-fallback.html
135137
```

docs/how-to/spa.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,33 @@ export default {
2323

2424
With this set to false, the server build will no longer be generated.
2525

26-
## 2. Use client loaders and client actions
26+
## 2. Add a `HydrateFallback` to your root route
27+
28+
SPA Mode will generate an `index.html` file at build-time that you can serve as the entry point for your SPA. This will only render the root route so that it is capable of hydrating at runtime for any path in your application.
29+
30+
To provide a better/faster loading UI, you can add a `HydrateFallback` component to your root route to render your loading UI into the `index.html` at build time. This way, it will be shown to users immediately while the SPA is loading/hydrating.
31+
32+
```tsx filename=root.tsx
33+
import { Route } from "./+types/root";
34+
import AwesomeSpinner from "./components/spinner";
35+
36+
export function Layout() {
37+
return <html>{/*...*/}</html>;
38+
}
39+
40+
// Server-rendered at build time into `index.html` (inside `<Layout>`)
41+
export function HydrateFallback() {
42+
return <AwesomeSpinner />;
43+
}
44+
45+
export default function App() {
46+
return <Outlet />;
47+
}
48+
```
49+
50+
Because the root route is server-rendered at build time, you can also use a `loader` in your root route if you choose, and access the data via the optional `HydrateFallback` `loaderData` prop. You cannot in include a loader in any other routes in your app when using SPA Mode.
51+
52+
## 3. Use client loaders and client actions
2753

2854
With server rendering disabled, you can still use `clientLoader` and `clientAction` to manage route data and mutations.
2955

@@ -45,11 +71,11 @@ export async function clientAction({
4571
}
4672
```
4773

48-
## 3. Pre-rendering
74+
## 4. Pre-rendering
4975

5076
Pre-rendering can be configured for paths with static data known at build time for faster initial page loads. Refer to [Pre-rendering](./pre-rendering) to set it up.
5177

52-
## 4. Direct all URLs to index.html
78+
## 5. Direct all URLs to index.html
5379

5480
After running `react-router build`, deploy the `build/client` directory to whatever static host you prefer.
5581

integration/vite-prerender-test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,8 @@ test.describe("Prerendering", () => {
745745
let stderr = result.stderr.toString("utf8");
746746
expect(stderr).toMatch(
747747
"Prerender: 2 invalid route export(s) in `routes/a` when prerendering " +
748-
"with `ssr:false`: headers, action. See https://reactrouter.com/how-to/spa for more information."
748+
"with `ssr:false`: headers, action. " +
749+
"See https://reactrouter.com/how-to/pre-rendering for more information."
749750
);
750751
});
751752

@@ -773,8 +774,8 @@ test.describe("Prerendering", () => {
773774
expect(stderr).toMatch(
774775
"Prerender: 1 invalid route export in `routes/b` when using `ssr:false` " +
775776
"with `prerender` because the route is never prerendered so the loader " +
776-
"will never be called. See https://reactrouter.com/how-to/spa for more " +
777-
"information."
777+
"will never be called. See https://reactrouter.com/how-to/pre-rendering " +
778+
"for more information."
778779
);
779780
});
780781

packages/react-router-dev/vite/plugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2643,7 +2643,7 @@ async function validateSsrFalsePrerenderExports(
26432643
`Prerender: ${invalidApis.length} invalid route export(s) in ` +
26442644
`\`${route.id}\` when prerendering with \`ssr:false\`: ` +
26452645
`${invalidApis.join(", ")}. ` +
2646-
"See https://reactrouter.com/how-to/spa for more information."
2646+
"See https://reactrouter.com/how-to/pre-rendering for more information."
26472647
);
26482648
}
26492649

@@ -2653,7 +2653,7 @@ async function validateSsrFalsePrerenderExports(
26532653
`Prerender: 1 invalid route export in \`${route.id}\` when ` +
26542654
"using `ssr:false` with `prerender` because the route is never " +
26552655
"prerendered so the loader will never be called. " +
2656-
"See https://reactrouter.com/how-to/spa for more information."
2656+
"See https://reactrouter.com/how-to/pre-rendering for more information."
26572657
);
26582658
}
26592659
}

0 commit comments

Comments
 (0)