/
use-flight-response.tsx
78 lines (70 loc) · 2.37 KB
/
use-flight-response.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin'
import type { FlightResponseRef } from './flight-response-ref'
import { readableStreamTee } from '../stream-utils/node-web-streams-helper'
import { encodeText, decodeText } from '../stream-utils/encode-decode'
import { htmlEscapeJsonString } from '../htmlescape'
const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'
/**
* Render Flight stream.
* This is only used for renderToHTML, the Flight response does not need additional wrappers.
*/
export function useFlightResponse(
writable: WritableStream<Uint8Array>,
req: ReadableStream<Uint8Array>,
clientReferenceManifest: ClientReferenceManifest,
rscChunks: Uint8Array[],
flightResponseRef: FlightResponseRef,
nonce?: string
): Promise<JSX.Element> {
if (flightResponseRef.current !== null) {
return flightResponseRef.current
}
const {
createFromReadableStream,
} = require(`react-server-dom-webpack/client.edge`)
const [renderStream, forwardStream] = readableStreamTee(req)
const res = createFromReadableStream(renderStream, {
moduleMap: isEdgeRuntime
? clientReferenceManifest.edgeSSRModuleMapping
: clientReferenceManifest.ssrModuleMapping,
})
flightResponseRef.current = res
let bootstrapped = false
// We only attach CSS chunks to the inlined data.
const forwardReader = forwardStream.getReader()
const writer = writable.getWriter()
const startScriptTag = nonce
? `<script nonce=${JSON.stringify(nonce)}>`
: '<script>'
const textDecoder = new TextDecoder()
function read() {
forwardReader.read().then(({ done, value }) => {
if (value) {
rscChunks.push(value)
}
if (!bootstrapped) {
bootstrapped = true
writer.write(
encodeText(
`${startScriptTag}(self.__next_f=self.__next_f||[]).push(${htmlEscapeJsonString(
JSON.stringify([0])
)})</script>`
)
)
}
if (done) {
flightResponseRef.current = null
writer.close()
} else {
const responsePartial = decodeText(value, textDecoder)
const scripts = `${startScriptTag}self.__next_f.push(${htmlEscapeJsonString(
JSON.stringify([1, responsePartial])
)})</script>`
writer.write(encodeText(scripts))
read()
}
})
}
read()
return res
}