Skip to content

Commit b87dadf

Browse files
committed
Add logging back to entry-server for streamed html chunks
1 parent 403b5d9 commit b87dadf

File tree

4 files changed

+35
-0
lines changed

4 files changed

+35
-0
lines changed

docs/file-conventions/entry.server.md

+15
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ export function onUnhandledError(
3737
}
3838
```
3939

40+
### Streaming Rendering Errors
41+
42+
When you are streaming your HTML responses via [`renderToPipeableStream`][rendertopipeablestream] or [`renderToReadableStream`][rendertoreadablestream], your own `onUnhandledError` implementation will only handle errors encountered uring the initial shell render. If you encounter a rendering error during subsequent streamed rendering you will need handle these errors manually since the Remix server has already sent the Response by that point.
43+
44+
- For `renderToPipeableStream`, you can handle these errors in the `onError` callback function. You will need to toggle a boolean when the in `onShellReady` so you know if the error was a shell rendering error (and can be ignored) or an async rendering error (and must be handled).
45+
- For an exmaple, please see the default [`entry.server.tsx`][node-streaming-entry-server] for Node.
46+
- For `renderToReadableStream`, you can handle these errors in the `onError` callback function
47+
- For an example, please see the default [`entry.server.tsx`][cloudflare-streaming-entry-server] for Cloudflare
48+
49+
### Thrown Responses
50+
4051
Note that this does not handle thrown `Response` instances from your `loader`/`action` functions. The intention of this handler is to find bugs in your code which result in unexpected thrown errors. If you are detecting a scenario and throwing a 401/404/etc. `Response` in your `loader`/`action` then it's an expected flow that is handled by your code. If you also wish to log, or send those to an external service, that should be done at the time you throw the response.
4152

4253
[browser-entry-module]: ./entry.client
54+
[rendertopipeablestream]: https://react.dev/reference/react-dom/server/renderToPipeableStream
55+
[rendertoreadablestream]: https://react.dev/reference/react-dom/server/renderToReadableStream
56+
[node-streaming-entry-server]: https://github.com/remix-run/remix/blob/main/packages/remix-dev/config/defaults/node/entry.server.react-stream.tsx
57+
[cloudflare-streaming-entry-server]: https://github.com/remix-run/remix/blob/main/packages/remix-dev/config/defaults/cloudflare/entry.server.react-stream.tsx

packages/remix-dev/config/defaults/cloudflare/entry.server.react-stream.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export default async function handleRequest(
1414
{
1515
signal: request.signal,
1616
onError(error: unknown) {
17+
// Log streaming rendering errors from inside the shell
18+
console.error(error);
1719
responseStatusCode = 500;
1820
},
1921
}

packages/remix-dev/config/defaults/deno/entry.server.react-stream.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export default async function handleRequest(
1414
{
1515
signal: request.signal,
1616
onError(error: unknown) {
17+
// Log streaming rendering errors from inside the shell
18+
console.error(error);
1719
responseStatusCode = 500;
1820
},
1921
}

packages/remix-dev/config/defaults/node/entry.server.react-stream.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ function handleBotRequest(
3636
remixContext: EntryContext
3737
) {
3838
return new Promise((resolve, reject) => {
39+
let shellRendered = false;
3940
const { pipe, abort } = renderToPipeableStream(
4041
<RemixServer
4142
context={remixContext}
@@ -44,6 +45,7 @@ function handleBotRequest(
4445
/>,
4546
{
4647
onAllReady() {
48+
shellRendered = true;
4749
const body = new PassThrough();
4850

4951
responseHeaders.set("Content-Type", "text/html");
@@ -62,6 +64,12 @@ function handleBotRequest(
6264
},
6365
onError(error: unknown) {
6466
responseStatusCode = 500;
67+
// Log streaming rendering errors from inside the shell. Don't log
68+
// errors encountered during initial shell rendering since they'll
69+
// reject and get logged in handleDocumentRequest.
70+
if (shellRendered) {
71+
console.error(error);
72+
}
6573
},
6674
}
6775
);
@@ -77,6 +85,7 @@ function handleBrowserRequest(
7785
remixContext: EntryContext
7886
) {
7987
return new Promise((resolve, reject) => {
88+
let shellRendered = false;
8089
const { pipe, abort } = renderToPipeableStream(
8190
<RemixServer
8291
context={remixContext}
@@ -85,6 +94,7 @@ function handleBrowserRequest(
8594
/>,
8695
{
8796
onShellReady() {
97+
shellRendered = true;
8898
const body = new PassThrough();
8999

90100
responseHeaders.set("Content-Type", "text/html");
@@ -103,6 +113,12 @@ function handleBrowserRequest(
103113
},
104114
onError(error: unknown) {
105115
responseStatusCode = 500;
116+
// Log streaming rendering errors from inside the shell. Don't log
117+
// errors encountered during initial shell rendering since they'll
118+
// reject and get logged in handleDocumentRequest.
119+
if (shellRendered) {
120+
console.error(error);
121+
}
106122
},
107123
}
108124
);

0 commit comments

Comments
 (0)