@@ -3,7 +3,6 @@ import { PassThrough } from "node:stream";
33import type { AppLoadContext , EntryContext } from "@react-router/node" ;
44import { createReadableStreamFromReadable } from "@react-router/node" ;
55import { RemixServer } from "react-router" ;
6- import * as isbotModule from "isbot" ;
76import { renderToPipeableStream } from "react-dom/server" ;
87
98const ABORT_DELAY = 5_000 ;
@@ -15,43 +14,12 @@ export default function handleRequest(
1514 remixContext : EntryContext ,
1615 loadContext : AppLoadContext
1716) {
18- let prohibitOutOfOrderStreaming =
19- isBotRequest ( request . headers . get ( "user-agent" ) ) || remixContext . isSpaMode ;
20-
21- return prohibitOutOfOrderStreaming
22- ? handleBotRequest (
23- request ,
24- responseStatusCode ,
25- responseHeaders ,
26- remixContext
27- )
28- : handleBrowserRequest (
29- request ,
30- responseStatusCode ,
31- responseHeaders ,
32- remixContext
33- ) ;
34- }
35-
36- // We have some Remix apps in the wild already running with isbot@3 so we need
37- // to maintain backwards compatibility even though we want new apps to use
38- // isbot@4. That way, we can ship this as a minor Semver update to @react-router/dev.
39- function isBotRequest ( userAgent : string | null ) {
40- if ( ! userAgent ) {
41- return false ;
42- }
43-
44- // isbot >= 3.8.0, >4
45- if ( "isbot" in isbotModule && typeof isbotModule . isbot === "function" ) {
46- return isbotModule . isbot ( userAgent ) ;
47- }
48-
49- // isbot < 3.8.0
50- if ( "default" in isbotModule && typeof isbotModule . default === "function" ) {
51- return isbotModule . default ( userAgent ) ;
52- }
53-
54- return false ;
17+ return handleBotRequest (
18+ request ,
19+ responseStatusCode ,
20+ responseHeaders ,
21+ remixContext
22+ ) ;
5523}
5624
5725function handleBotRequest (
@@ -103,53 +71,3 @@ function handleBotRequest(
10371 setTimeout ( abort , ABORT_DELAY ) ;
10472 } ) ;
10573}
106-
107- function handleBrowserRequest (
108- request : Request ,
109- responseStatusCode : number ,
110- responseHeaders : Headers ,
111- remixContext : EntryContext
112- ) {
113- return new Promise ( ( resolve , reject ) => {
114- let shellRendered = false ;
115- const { pipe, abort } = renderToPipeableStream (
116- < RemixServer
117- context = { remixContext }
118- url = { request . url }
119- abortDelay = { ABORT_DELAY }
120- /> ,
121- {
122- onShellReady ( ) {
123- shellRendered = true ;
124- const body = new PassThrough ( ) ;
125- const stream = createReadableStreamFromReadable ( body ) ;
126-
127- responseHeaders . set ( "Content-Type" , "text/html" ) ;
128-
129- resolve (
130- new Response ( stream , {
131- headers : responseHeaders ,
132- status : responseStatusCode ,
133- } )
134- ) ;
135-
136- pipe ( body ) ;
137- } ,
138- onShellError ( error : unknown ) {
139- reject ( error ) ;
140- } ,
141- onError ( error : unknown ) {
142- responseStatusCode = 500 ;
143- // Log streaming rendering errors from inside the shell. Don't log
144- // errors encountered during initial shell rendering since they'll
145- // reject and get logged in handleDocumentRequest.
146- if ( shellRendered ) {
147- console . error ( error ) ;
148- }
149- } ,
150- }
151- ) ;
152-
153- setTimeout ( abort , ABORT_DELAY ) ;
154- } ) ;
155- }
0 commit comments