Skip to content

Commit

Permalink
fix: multi-byte-streaming-ssr
Browse files Browse the repository at this point in the history
When using streaming SSR decodeText is called repeatedly with incoming
chunks of data. In that case a multi-byte character may occasionally
split between chunks, causing corruption. By setting the TextDecoder
option 'stream' to true, and reusing the same TextDecoder instance,
TextDecoder will memorise “unfinished” characters and decode them when
the next chunk comes.
  • Loading branch information
martinnabhan committed Mar 30, 2022
1 parent 050936c commit 04cf4c9
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
10 changes: 7 additions & 3 deletions packages/next/server/node-web-streams-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ export function encodeText(input: string) {
return new TextEncoder().encode(input)
}

export function decodeText(input?: Uint8Array) {
return new TextDecoder().decode(input)
export function decodeText(input?: Uint8Array, textDecoder?: TextDecoder) {
return textDecoder
? textDecoder.decode(input, { stream: true })
: new TextDecoder().decode(input)
}

export function createTransformStream<Input, Output>({
Expand Down Expand Up @@ -207,9 +209,11 @@ export function createBufferedTransformStream(): TransformStream<
return pendingFlush
}

const textDecoder = new TextDecoder()

return createTransformStream({
transform(chunk, controller) {
bufferedString += decodeText(chunk)
bufferedString += decodeText(chunk, textDecoder)
flushBuffer(controller)
},

Expand Down
14 changes: 14 additions & 0 deletions test/production/react-18-streaming-ssr/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ describe('react 18 streaming SSR with custom next configs', () => {
return <p>hello nextjs</p>
}
`,
'pages/multi-byte.js': `
export default function Page() {
return (
<div>
<p>{"マルチバイト".repeat(28)}</p>
</div>
);
}
`,
},
nextConfig: {
trailingSlash: true,
Expand Down Expand Up @@ -98,4 +107,9 @@ describe('react 18 streaming SSR with custom next configs', () => {
expect(res.status).toBe(200)
expect(html).toContain('hello nextjs')
})

it('should render multi-byte characters correctly in streaming', async () => {
const html = await renderViaHTTP(next.url, '/multi-byte')
expect(html).toContain('マルチバイト'.repeat(28))
})
})

0 comments on commit 04cf4c9

Please sign in to comment.