Push V1 app
This commit is contained in:
+225
@@ -0,0 +1,225 @@
|
||||
---
|
||||
title: Pre-Rendering
|
||||
---
|
||||
|
||||
# Pre-Rendering
|
||||
|
||||
[MODES: framework]
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
Pre-Rendering allows you to speed up page loads for static content by rendering pages at build time instead of at runtime.
|
||||
|
||||
## Configuration
|
||||
|
||||
Pre-rendering is enabled via the `prerender` config in `react-router.config.ts`.
|
||||
|
||||
The simplest configuration is a boolean `true` which will pre-render all off the applications static paths based on `routes.ts`:
|
||||
|
||||
```ts filename=react-router.config.ts
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
prerender: true,
|
||||
} satisfies Config;
|
||||
```
|
||||
|
||||
The boolean `true` will not include any dynamic paths (i.e., `/blog/:slug`) because the parameter values are unknown.
|
||||
|
||||
To configure specific paths including dynamic values, you can specify an array of paths:
|
||||
|
||||
```ts filename=react-router.config.ts
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
let slugs = getPostSlugs();
|
||||
|
||||
export default {
|
||||
prerender: [
|
||||
"/",
|
||||
"/blog",
|
||||
...slugs.map((s) => `/blog/${s}`),
|
||||
],
|
||||
} satisfies Config;
|
||||
```
|
||||
|
||||
If you need to perform more complex and/or asynchronous logic to determine the paths, you can also provide a function that returns an array of paths. This function provides you with a `getStaticPaths` method you can use to avoid manually adding all of the static paths in your application:
|
||||
|
||||
```ts filename=react-router.config.ts
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
async prerender({ getStaticPaths }) {
|
||||
let slugs = await getPostSlugsFromCMS();
|
||||
return [
|
||||
...getStaticPaths(), // "/" and "/blog"
|
||||
...slugs.map((s) => `/blog/${s}`),
|
||||
];
|
||||
},
|
||||
} satisfies Config;
|
||||
```
|
||||
|
||||
### Concurrency
|
||||
|
||||
By default, pages are pre-rendered one path at a time. You can enable concurrency to pre-render multiple paths in parallel which can speed up build times in many cases. You should experiment with the value that provides the best performance for your app.
|
||||
|
||||
To specify concurrency, move your `prerender` config down into a `prerender.paths` field and you can specify the concurrency in `prerender.concurrency`:
|
||||
|
||||
```ts filename=react-router.config.ts
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
let slugs = getPostSlugs();
|
||||
|
||||
export default {
|
||||
prerender: {
|
||||
paths: [
|
||||
"/",
|
||||
"/blog",
|
||||
...slugs.map((s) => `/blog/${s}`),
|
||||
],
|
||||
concurrency: 4,
|
||||
},
|
||||
} satisfies Config;
|
||||
```
|
||||
|
||||
## Pre-Rendering with/without a Runtime Server
|
||||
|
||||
Pre-Rendering can be used in two ways based on the `ssr` config value:
|
||||
|
||||
- Alongside a runtime SSR server with `ssr:true` (the default value)
|
||||
- Deployed to a static file server with `ssr:false`
|
||||
|
||||
### Pre-rendering with `ssr:true`
|
||||
|
||||
When pre-rendering with `ssr:true`, you're indicating you will still have a runtime server but you are choosing to pre-render certain paths for quicker Response times.
|
||||
|
||||
```ts filename=react-router.config.ts
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
// Can be omitted - defaults to true
|
||||
ssr: true,
|
||||
prerender: ["/", "/blog", "/blog/popular-post"],
|
||||
} satisfies Config;
|
||||
```
|
||||
|
||||
#### Data Loading and Pre-rendering
|
||||
|
||||
There is no extra application API for pre-rendering. Routes being pre-rendered use the same route `loader` functions as server rendering:
|
||||
|
||||
```tsx
|
||||
export async function loader({ request, params }) {
|
||||
let post = await getPost(params.slug);
|
||||
return post;
|
||||
}
|
||||
|
||||
export function Post({ loaderData }) {
|
||||
return <div>{loaderData.title}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
Instead of a request coming to your route on a deployed server, the build creates a `new Request()` and runs it through your app just like a server would.
|
||||
|
||||
When server rendering, requests to paths that have not been pre-rendered will be server rendered as usual.
|
||||
|
||||
#### Static File Output
|
||||
|
||||
The rendered result will be written out to your `build/client` directory. You'll notice two files for each path:
|
||||
|
||||
- `[url].html` HTML file for initial document requests
|
||||
- `[url].data` file for client side navigation browser requests
|
||||
|
||||
The output of your build will indicate what files were pre-rendered:
|
||||
|
||||
```sh
|
||||
> react-router build
|
||||
vite v5.2.11 building for production...
|
||||
...
|
||||
vite v5.2.11 building SSR bundle for production...
|
||||
...
|
||||
Prerender: Generated build/client/index.html
|
||||
Prerender: Generated build/client/blog.data
|
||||
Prerender: Generated build/client/blog/index.html
|
||||
Prerender: Generated build/client/blog/my-first-post.data
|
||||
Prerender: Generated build/client/blog/my-first-post/index.html
|
||||
...
|
||||
```
|
||||
|
||||
During development, pre-rendering doesn't save the rendered results to the public directory, this only happens for `react-router build`.
|
||||
|
||||
### Pre-rendering with `ssr:false`
|
||||
|
||||
The above examples assume you are deploying a runtime server but are pre-rendering some static pages to avoid hitting the server, resulting in faster loads.
|
||||
|
||||
To disable runtime SSR and configure pre-rendering to be served from a static file server, you can set the `ssr:false` config flag:
|
||||
|
||||
```ts filename=react-router.config.ts
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
ssr: false, // disable runtime server rendering
|
||||
prerender: true, // pre-render all static routes
|
||||
} satisfies Config;
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
#### Pre-rendering with a SPA Fallback
|
||||
|
||||
If you want `ssr:false` but don't want to pre-render _all_ of your routes - that's fine too! You may have some paths where you need the performance/SEO benefits of pre-rendering, but other pages where a SPA would be fine.
|
||||
|
||||
You can do this using the combination of config options as well - just limit your `prerender` config to the paths that you want to pre-render and React Router will also output a "SPA Fallback" HTML file that can be served to hydrate any other paths (using the same approach as [SPA Mode](./spa)).
|
||||
|
||||
This will be written to one of the following paths:
|
||||
|
||||
- `build/client/index.html` - If the `/` path is not pre-rendered
|
||||
- `build/client/__spa-fallback.html` - If the `/` path is pre-rendered
|
||||
|
||||
```ts filename=react-router.config.ts
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
ssr: false,
|
||||
|
||||
// SPA fallback will be written to build/client/index.html
|
||||
prerender: ["/about-us"],
|
||||
|
||||
// SPA fallback will be written to build/client/__spa-fallback.html
|
||||
prerender: ["/", "/about-us"],
|
||||
} satisfies Config;
|
||||
```
|
||||
|
||||
You can configure your deployment server to serve this file for any path that otherwise would 404. Some hosts do this by default, but others don't. As an example, a host may support a `_redirects` file to do this:
|
||||
|
||||
```
|
||||
# If you did not pre-render the `/` route
|
||||
/* /index.html 200
|
||||
|
||||
# If you pre-rendered the `/` route
|
||||
/* /__spa-fallback.html 200
|
||||
```
|
||||
|
||||
If you're getting 404s at valid routes for your app, it's likely you need to configure your host.
|
||||
|
||||
Here's another example of how you can do this with the [`sirv-cli`](https://www.npmjs.com/package/sirv-cli#user-content-single-page-applications) tool:
|
||||
|
||||
```sh
|
||||
# If you did not pre-render the `/` route
|
||||
sirv-cli build/client --single index.html
|
||||
|
||||
# If you pre-rendered the `/` route
|
||||
sirv-cli build/client --single __spa-fallback.html
|
||||
```
|
||||
|
||||
#### Invalid Exports
|
||||
|
||||
When pre-rendering with `ssr:false`, React Router will error at build time if you have invalid exports to help prevent some mistakes that can be easily overlooked.
|
||||
|
||||
- `headers`/`action` functions are prohibited in all routes because there will be no runtime server on which to run them
|
||||
- When using `ssr:false` without a `prerender` config (SPA Mode), a `loader` is permitted on the root route only
|
||||
- When using `ssr:false` with a `prerender` config, a `loader` is permitted on any route matched by a `prerender` path
|
||||
- If you are using a `loader` on a pre-rendered route that has child routes, you will need to make sure the parent `loaderData` can be determined at run-time properly by either:
|
||||
- Pre-rendering all child routes so that the parent `loader` can be called at build-time for each child route path and rendered into a `.data` file, or
|
||||
- Use a `clientLoader` on the parent that can be called at run-time for non-pre-rendered child paths
|
||||
Reference in New Issue
Block a user