Skip to content

Commit 614153d

Browse files
committed
Init PPR docs
1 parent 84a5696 commit 614153d

File tree

7 files changed

+520
-9
lines changed

7 files changed

+520
-9
lines changed

next-env.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3+
/// <reference types="next/navigation-types/compat/navigation" />
34

45
// NOTE: This file should not be edited
5-
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
6+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

src/content/reference/react-dom/server/index.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@ The `react-dom/server` APIs let you server-side render React components to HTML.
1010

1111
---
1212

13-
## Server APIs for Node.js Streams {/*server-apis-for-nodejs-streams*/}
14-
15-
These methods are only available in the environments with [Node.js Streams:](https://nodejs.org/api/stream.html)
13+
## Server APIs for Web Streams {/*server-apis-for-web-streams*/}
1614

17-
* [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) renders a React tree to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html)
15+
These methods are only available in the environments with [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), which includes browsers, Deno, and some modern edge runtimes:
1816

17+
* [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream) renders a React tree to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
18+
* [`resume`](/reference/react-dom/server/renderToPipeableStream) resumes [`prerender`](/reference/react-dom/static/prerender) to a [Readable Web Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
1919
---
2020

21-
## Server APIs for Web Streams {/*server-apis-for-web-streams*/}
21+
## Server APIs for Node.js Streams {/*server-apis-for-nodejs-streams*/}
2222

23-
These methods are only available in the environments with [Web Streams](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), which includes browsers, Deno, and some modern edge runtimes:
23+
These methods are only available in the environments with [Node.js Streams:](https://nodejs.org/api/stream.html)
2424

25-
* [`renderToReadableStream`](/reference/react-dom/server/renderToReadableStream) renders a React tree to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
25+
* [`renderToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) renders a React tree to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html)
26+
* [`resumeToPipeableStream`](/reference/react-dom/server/renderToPipeableStream) resumes [`prerenderToNodeStream`](/reference/react-dom/static/prerenderToNodeStream) to a pipeable [Node.js Stream.](https://nodejs.org/api/stream.html)
2627

2728
---
2829

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
---
2+
title: resume
3+
canary: true
4+
---
5+
6+
<Intro>
7+
8+
`resume` streams a pre-rendered React tree to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
9+
10+
```js
11+
const stream = await resume(reactNode, postponedState, options?)
12+
```
13+
14+
</Intro>
15+
16+
<InlineToc />
17+
18+
<Note>
19+
20+
This API depends on [Web Streams.](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) For Node.js, use [`resumeToNodeStream`](/reference/react-dom/server/renderToPipeableStream) instead.
21+
22+
</Note>
23+
24+
---
25+
26+
## Reference {/*reference*/}
27+
28+
### `resume(node, postponed, options?)` {/*resume*/}
29+
30+
Call `resume` to resume rendering a pre-rendered React tree as HTML into a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
31+
32+
```js
33+
import { resume } from 'react-dom/server';
34+
import {getPostponedState} from 'storage';
35+
36+
async function handler(request) {
37+
const postponed = await getPostponedState(request);
38+
const stream = await resume(<App />, postponed, {
39+
bootstrapScripts: ['/main.js']
40+
});
41+
return new Response(stream, {
42+
headers: { 'content-type': 'text/html' },
43+
});
44+
}
45+
```
46+
47+
TODO: when do you call hydrateRoot? In the shell or when you resume?
48+
49+
[See more examples below.](#usage)
50+
51+
#### Parameters {/*parameters*/}
52+
53+
* `reactNode`: The React node you called `prerender` with. For example, a JSX element like `<App />`. It is expected to represent the entire document, so the `App` component should render the `<html>` tag.
54+
* `postponedState`: The opaque `postpone` object returned from `prerender`, loaded from wherever you stored it (e.g. redis, a file, or S3).
55+
* **optional** `options`: An object with streaming options.
56+
* **optional** `nonce`: A [`nonce`](http://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#nonce) string to allow scripts for [`script-src` Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src).
57+
* **optional** `signal`: An [abort signal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that lets you [abort server rendering](#aborting-server-rendering) and render the rest on the client.
58+
* **optional** `onError`: A callback that fires whenever there is a server error, whether [recoverable](#recovering-from-errors-outside-the-shell) or [not.](#recovering-from-errors-inside-the-shell) By default, this only calls `console.error`. If you override it to [log crash reports,](#logging-crashes-on-the-server) make sure that you still call `console.error`.
59+
60+
61+
#### Returns {/*returns*/}
62+
63+
`resume` returns a Promise:
64+
65+
- If `prerender` successfully produced a [shell](#specifying-what-goes-into-the-shell) is successful, that Promise will resolve to a [Readable Web Stream.](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) whether replaying the shell errors or not.
66+
- If `prerender` failed to produce a [shell](#specifying-what-goes-into-the-shell), and `resume` errors, the Promise will be rejected. TODO: Example?
67+
68+
The returned stream has an additional property:
69+
70+
* `allReady`: A Promise that resolves when all rendering is complete. You can `await stream.allReady` before returning a response [for crawlers and static generation.](#waiting-for-all-content-to-load-for-crawlers-and-static-generation) If you do that, you won't get any progressive loading. The stream will contain the final HTML.
71+
72+
#### Caveats {/*caveats*/}
73+
- `resume` does not accept options for `bootstrapScripts`, `bootstrapScriptContent`, or `bootstrapModules`. Instead, you need to pass these options to the `prerender` call that generates the `postponedState`. These may be injected either during pre-render or resume.
74+
- `resume` does not accept `identifierPrefix` since the prefix needs to be the same in both `prerender` and `resume`.
75+
- Since `nonce` cannot be provided to prerender, you should only provide `nonce` to `resume` if you're not providing scripts to prerender.
76+
- `resume` re-renders from the root until it finds a component that was not fully pre-rendered, and skips fully pre-rendered components.
77+
---
78+
79+
## Usage {/*usage*/}
80+
81+
### Resuming a prerender to a Readable Web Stream {/*resuming-a-prerender-to-a-readable-web-stream*/}
82+
83+
TODO
84+
85+
---
86+
87+
### Logging crashes on the server {/*logging-crashes-on-the-server*/}
88+
89+
By default, all errors on the server are logged to console. You can override this behavior to log crash reports:
90+
91+
```js {9-10}
92+
import { resume } from 'react-dom/server';
93+
import { getPostponedState } from 'storage';
94+
import { logServerCrashReport } from 'logging';
95+
96+
async function handler(request) {
97+
const postponed = await getPostponedState(request);
98+
const stream = await resume(<App />, postponed, {
99+
onError(error) {
100+
console.error(error);
101+
logServerCrashReport(error);
102+
}
103+
});
104+
return new Response(stream, {
105+
headers: { 'content-type': 'text/html' },
106+
});
107+
}
108+
```
109+
110+
If you provide a custom `onError` implementation, don't forget to also log errors to the console like above.
111+
112+
---
113+
114+
### Recovering from errors replaying the shell {/*recovering-from-errors-inside-the-shell*/}
115+
116+
TODO: this is for when the shell completed.
117+
118+
In this example, prerender successfully rendered a shell containing `ProfileLayout`, `ProfileCover`, and `PostsGlimmer`:
119+
120+
```js {3-5,7-8}
121+
function ProfilePage() {
122+
return (
123+
<ProfileLayout>
124+
<ProfileCover />
125+
<Suspense fallback={<PostsGlimmer />}>
126+
<Posts />
127+
</Suspense>
128+
</ProfileLayout>
129+
);
130+
}
131+
```
132+
133+
If an error occurs while replaying those components, React won't have any meaningful HTML to send to the client. TODO: how to recover from this, since the promise is resolved. I think it will just encode an error in the stream and trigger an error boundary?
134+
135+
```js {2,13-18}
136+
// TODO
137+
```
138+
139+
If there is an error while replaying the shell, it will be logged to `onError`.
140+
141+
### Recovering from errors re-creating the shell {/*recovering-from-errors-re-creating-the-shell*/}
142+
143+
TODO: this is for when the shell errors, and re-creating the shell fails.
144+
145+
---
146+
147+
### Recovering from errors outside the shell {/*recovering-from-errors-outside-the-shell*/}
148+
149+
TODO: confirm this section is correct.
150+
151+
In this example, the `<Posts />` component is wrapped in `<Suspense>` so it is *not* a part of the shell:
152+
153+
```js {6}
154+
function ProfilePage() {
155+
return (
156+
<ProfileLayout>
157+
<ProfileCover />
158+
<Suspense fallback={<PostsGlimmer />}>
159+
<Posts />
160+
</Suspense>
161+
</ProfileLayout>
162+
);
163+
}
164+
```
165+
166+
If an error happens in the `Posts` component or somewhere inside it, React will [try to recover from it:](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content)
167+
168+
1. It will emit the loading fallback for the closest `<Suspense>` boundary (`PostsGlimmer`) into the HTML.
169+
2. It will "give up" on trying to render the `Posts` content on the server anymore.
170+
3. When the JavaScript code loads on the client, React will *retry* rendering `Posts` on the client.
171+
172+
If retrying rendering `Posts` on the client *also* fails, React will throw the error on the client. As with all the errors thrown during rendering, the [closest parent error boundary](/reference/react/Component#static-getderivedstatefromerror) determines how to present the error to the user. In practice, this means that the user will see a loading indicator until it is certain that the error is not recoverable.
173+
174+
If retrying rendering `Posts` on the client succeeds, the loading fallback from the server will be replaced with the client rendering output. The user will not know that there was a server error. However, the server `onError` callback and the client [`onRecoverableError`](/reference/react-dom/client/hydrateRoot#hydrateroot) callbacks will fire so that you can get notified about the error.
175+
176+
---
177+
178+
### Setting the status code {/*setting-the-status-code*/}
179+
180+
TODO: you can't set the status code in resume, unless you're calling prerender in the same request. If so, set the status code between `prerender` and `resume`.
181+
182+
---
183+
184+
### Handling different errors in different ways {/*handling-different-errors-in-different-ways*/}
185+
186+
TODO: update this example.
187+
188+
You can [create your own `Error` subclasses](https://javascript.info/custom-errors) and use the [`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) operator to check which error is thrown. For example, you can define a custom `NotFoundError` and throw it from your component. Then you can save the error in `onError` and do something different before returning the response depending on the error type:
189+
190+
```js {2-3,5-15,22,28,33}
191+
async function handler(request) {
192+
let didError = false;
193+
let caughtError = null;
194+
195+
function getStatusCode() {
196+
if (didError) {
197+
if (caughtError instanceof NotFoundError) {
198+
return 404;
199+
} else {
200+
return 500;
201+
}
202+
} else {
203+
return 200;
204+
}
205+
}
206+
207+
try {
208+
const stream = await renderToReadableStream(<App />, {
209+
bootstrapScripts: ['/main.js'],
210+
onError(error) {
211+
didError = true;
212+
caughtError = error;
213+
console.error(error);
214+
logServerCrashReport(error);
215+
}
216+
});
217+
return new Response(stream, {
218+
status: getStatusCode(),
219+
headers: { 'content-type': 'text/html' },
220+
});
221+
} catch (error) {
222+
return new Response('<h1>Something went wrong</h1>', {
223+
status: getStatusCode(),
224+
headers: { 'content-type': 'text/html' },
225+
});
226+
}
227+
}
228+
```
229+
230+
---
231+
232+
### Waiting for all content to load for crawlers and static generation {/*waiting-for-all-content-to-load-for-crawlers-and-static-generation*/}
233+
234+
TODO: this doesn't make sense for `resume` right?
235+
236+
---
237+
238+
### Aborting server rendering {/*aborting-server-rendering*/}
239+
240+
TODO

0 commit comments

Comments
 (0)