4
4
* For more information, see https://remix.run/file-conventions/entry.server
5
5
*/
6
6
7
- import { PassThrough } from " node:stream" ;
7
+ import { PassThrough } from ' node:stream'
8
8
9
- import type { EntryContext } from " @remix-run/node" ;
10
- import { Response } from " @remix-run/node" ;
11
- import { RemixServer } from " @remix-run/react" ;
12
- import isbot from " isbot" ;
13
- import { renderToPipeableStream } from " react-dom/server" ;
9
+ import type { AppLoadContext , EntryContext } from ' @remix-run/node'
10
+ import { createReadableStreamFromReadable } from ' @remix-run/node'
11
+ import { RemixServer } from ' @remix-run/react'
12
+ import isbot from ' isbot'
13
+ import { renderToPipeableStream } from ' react-dom/server'
14
14
15
- const ABORT_DELAY = 5_000 ;
15
+ const ABORT_DELAY = 5_000
16
16
17
17
export default function handleRequest (
18
18
request : Request ,
19
19
responseStatusCode : number ,
20
20
responseHeaders : Headers ,
21
- remixContext : EntryContext
21
+ remixContext : EntryContext ,
22
+ loadContext : AppLoadContext
22
23
) {
23
- return isbot ( request . headers . get ( "user-agent" ) )
24
- ? handleBotRequest (
25
- request ,
26
- responseStatusCode ,
27
- responseHeaders ,
28
- remixContext
29
- )
30
- : handleBrowserRequest (
31
- request ,
32
- responseStatusCode ,
33
- responseHeaders ,
34
- remixContext
35
- ) ;
24
+ return isbot ( request . headers . get ( 'user-agent' ) )
25
+ ? handleBotRequest ( request , responseStatusCode , responseHeaders , remixContext )
26
+ : handleBrowserRequest ( request , responseStatusCode , responseHeaders , remixContext )
36
27
}
37
28
38
29
function handleBotRequest (
@@ -42,39 +33,43 @@ function handleBotRequest(
42
33
remixContext : EntryContext
43
34
) {
44
35
return new Promise ( ( resolve , reject ) => {
36
+ let shellRendered = false
45
37
const { pipe, abort } = renderToPipeableStream (
46
- < RemixServer
47
- context = { remixContext }
48
- url = { request . url }
49
- abortDelay = { ABORT_DELAY }
50
- /> ,
38
+ < RemixServer context = { remixContext } url = { request . url } abortDelay = { ABORT_DELAY } /> ,
51
39
{
52
40
onAllReady ( ) {
53
- const body = new PassThrough ( ) ;
41
+ shellRendered = true
42
+ const body = new PassThrough ( )
43
+ const stream = createReadableStreamFromReadable ( body )
54
44
55
- responseHeaders . set ( " Content-Type" , " text/html" ) ;
45
+ responseHeaders . set ( ' Content-Type' , ' text/html' )
56
46
57
47
resolve (
58
- new Response ( body , {
48
+ new Response ( stream , {
59
49
headers : responseHeaders ,
60
50
status : responseStatusCode ,
61
51
} )
62
- ) ;
52
+ )
63
53
64
- pipe ( body ) ;
54
+ pipe ( body )
65
55
} ,
66
56
onShellError ( error : unknown ) {
67
- reject ( error ) ;
57
+ reject ( error )
68
58
} ,
69
59
onError ( error : unknown ) {
70
- responseStatusCode = 500 ;
71
- console . error ( error ) ;
60
+ responseStatusCode = 500
61
+ // Log streaming rendering errors from inside the shell. Don't log
62
+ // errors encountered during initial shell rendering since they'll
63
+ // reject and get logged in handleDocumentRequest.
64
+ if ( shellRendered ) {
65
+ console . error ( error )
66
+ }
72
67
} ,
73
68
}
74
- ) ;
69
+ )
75
70
76
- setTimeout ( abort , ABORT_DELAY ) ;
77
- } ) ;
71
+ setTimeout ( abort , ABORT_DELAY )
72
+ } )
78
73
}
79
74
80
75
function handleBrowserRequest (
@@ -84,37 +79,143 @@ function handleBrowserRequest(
84
79
remixContext : EntryContext
85
80
) {
86
81
return new Promise ( ( resolve , reject ) => {
82
+ let shellRendered = false
87
83
const { pipe, abort } = renderToPipeableStream (
88
- < RemixServer
89
- context = { remixContext }
90
- url = { request . url }
91
- abortDelay = { ABORT_DELAY }
92
- /> ,
84
+ < RemixServer context = { remixContext } url = { request . url } abortDelay = { ABORT_DELAY } /> ,
93
85
{
94
86
onShellReady ( ) {
95
- const body = new PassThrough ( ) ;
87
+ shellRendered = true
88
+ const body = new PassThrough ( )
89
+ const stream = createReadableStreamFromReadable ( body )
96
90
97
- responseHeaders . set ( " Content-Type" , " text/html" ) ;
91
+ responseHeaders . set ( ' Content-Type' , ' text/html' )
98
92
99
93
resolve (
100
- new Response ( body , {
94
+ new Response ( stream , {
101
95
headers : responseHeaders ,
102
96
status : responseStatusCode ,
103
97
} )
104
- ) ;
98
+ )
105
99
106
- pipe ( body ) ;
100
+ pipe ( body )
107
101
} ,
108
102
onShellError ( error : unknown ) {
109
- reject ( error ) ;
103
+ reject ( error )
110
104
} ,
111
105
onError ( error : unknown ) {
112
- console . error ( error ) ;
113
- responseStatusCode = 500 ;
106
+ responseStatusCode = 500
107
+ // Log streaming rendering errors from inside the shell. Don't log
108
+ // errors encountered during initial shell rendering since they'll
109
+ // reject and get logged in handleDocumentRequest.
110
+ if ( shellRendered ) {
111
+ console . error ( error )
112
+ }
114
113
} ,
115
114
}
116
- ) ;
115
+ )
117
116
118
- setTimeout ( abort , ABORT_DELAY ) ;
119
- } ) ;
117
+ setTimeout ( abort , ABORT_DELAY )
118
+ } )
120
119
}
120
+
121
+ // /**
122
+ // * By default, Remix will handle generating the HTTP Response for you.
123
+ // * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
124
+ // * For more information, see https://remix.run/file-conventions/entry.server
125
+ // */
126
+
127
+ // import { PassThrough } from 'node:stream'
128
+
129
+ // import type { EntryContext } from '@remix-run/node'
130
+ // import { RemixServer } from '@remix-run/react'
131
+ // import isbot from 'isbot'
132
+ // import { renderToPipeableStream } from 'react-dom/server'
133
+
134
+ // const ABORT_DELAY = 5_000
135
+
136
+ // export default function handleRequest(
137
+ // request: Request,
138
+ // responseStatusCode: number,
139
+ // responseHeaders: Headers,
140
+ // remixContext: EntryContext
141
+ // ) {
142
+ // return isbot(request.headers.get('user-agent'))
143
+ // ? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
144
+ // : handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext)
145
+ // }
146
+
147
+ // function handleBotRequest(
148
+ // request: Request,
149
+ // responseStatusCode: number,
150
+ // responseHeaders: Headers,
151
+ // remixContext: EntryContext
152
+ // ) {
153
+ // return new Promise((resolve, reject) => {
154
+ // const { pipe, abort } = renderToPipeableStream(
155
+ // <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
156
+ // {
157
+ // onAllReady() {
158
+ // const body = new PassThrough()
159
+
160
+ // responseHeaders.set('Content-Type', 'text/html')
161
+
162
+ // resolve(
163
+ // new Response(body, {
164
+ // headers: responseHeaders,
165
+ // status: responseStatusCode,
166
+ // })
167
+ // )
168
+
169
+ // pipe(body)
170
+ // },
171
+ // onShellError(error: unknown) {
172
+ // reject(error)
173
+ // },
174
+ // onError(error: unknown) {
175
+ // responseStatusCode = 500
176
+ // console.error(error)
177
+ // },
178
+ // }
179
+ // )
180
+
181
+ // setTimeout(abort, ABORT_DELAY)
182
+ // })
183
+ // }
184
+
185
+ // function handleBrowserRequest(
186
+ // request: Request,
187
+ // responseStatusCode: number,
188
+ // responseHeaders: Headers,
189
+ // remixContext: EntryContext
190
+ // ) {
191
+ // return new Promise((resolve, reject) => {
192
+ // const { pipe, abort } = renderToPipeableStream(
193
+ // <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
194
+ // {
195
+ // onShellReady() {
196
+ // const body = new PassThrough()
197
+
198
+ // responseHeaders.set('Content-Type', 'text/html')
199
+
200
+ // resolve(
201
+ // new Response(body, {
202
+ // headers: responseHeaders,
203
+ // status: responseStatusCode,
204
+ // })
205
+ // )
206
+
207
+ // pipe(body)
208
+ // },
209
+ // onShellError(error: unknown) {
210
+ // reject(error)
211
+ // },
212
+ // onError(error: unknown) {
213
+ // console.error(error)
214
+ // responseStatusCode = 500
215
+ // },
216
+ // }
217
+ // )
218
+
219
+ // setTimeout(abort, ABORT_DELAY)
220
+ // })
221
+ // }
0 commit comments