Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-web-missing-peer-deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@workflow/web": patch
---

Add custom `entry.server.tsx` and move `@react-router/node`, `isbot`, `react-router`, and `@react-router/express` to devDependencies since the build process bundles them entirely at build time
88 changes: 88 additions & 0 deletions packages/web/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { PassThrough } from 'node:stream';
import { createReadableStreamFromReadable } from '@react-router/node';
import { isbot } from 'isbot';
import type { RenderToPipeableStreamOptions } from 'react-dom/server';
import { renderToPipeableStream } from 'react-dom/server';
import type { AppLoadContext, EntryContext } from 'react-router';
import { ServerRouter } from 'react-router';

export const streamTimeout = 5_000;

/**
* This custom base request handler is based on the default react-router template, modified so that the `@react-router/dev` build plugin no longer requires `@react-router/node` and `isbot` in the dependencies field of `package.json`, allowing us to extract them as peer dependencies.
*/
export default function handleRequest(
Comment thread
TooTallNate marked this conversation as resolved.
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
routerContext: EntryContext,
loadContext: AppLoadContext
) {
// https://httpwg.org/specs/rfc9110.html#HEAD
if (request.method.toUpperCase() === 'HEAD') {
return new Response(null, {
status: responseStatusCode,
headers: responseHeaders,
});
}

return new Promise((resolve, reject) => {
let shellRendered = false;
const userAgent = request.headers.get('user-agent');

// Ensure requests from bots and SPA Mode renders wait for all content to load before responding
// https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation
const readyOption: keyof RenderToPipeableStreamOptions =
(userAgent && isbot(userAgent)) || routerContext.isSpaMode
? 'onAllReady'
: 'onShellReady';

// Abort the rendering stream after the `streamTimeout` so it has time to
// flush down the rejected boundaries
let timeoutId: ReturnType<typeof setTimeout> | undefined = setTimeout(
() => abort(),
streamTimeout + 1000
);

const { pipe, abort } = renderToPipeableStream(
<ServerRouter context={routerContext} url={request.url} />,
{
[readyOption]() {
shellRendered = true;
const body = new PassThrough({
final(callback) {
// Clear the timeout to prevent retaining the closure and memory leak
clearTimeout(timeoutId);
timeoutId = undefined;
callback();
},
});
const stream = createReadableStreamFromReadable(body);

responseHeaders.set('Content-Type', 'text/html');

pipe(body);

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);
});
}
4 changes: 1 addition & 3 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@
"test": "vitest run"
},
"dependencies": {
"@react-router/node": "7.13.1",
"express": "^4.21.0",
"isbot": "^5"
"express": "^4.21.0"
Comment thread
vercel[bot] marked this conversation as resolved.
},
"devDependencies": {
"@testing-library/react": "^16.3.0",
Expand Down
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading