Convert a ReadableStream to a String in JavaScript
21st May 2023
I have recently come across the need to convert a ReadableStream
to a String
. In my case this was because I was using React's react-dom/server
to render a component in an edge worker. More specifically, I needed to build an email body from ReMirror JSON content using their static renderer.
Using ReactDOMServer.renderToReadableStream.
The renderToReadableStream
method is the only option for rendering React DOM in a modern edge environment. That's ok, it's not hard to use a reader to build a string, chunk by chunk.
First, you need the stream and reader:
const stream = await ReactDOMServer.renderToReadableStream(createElement(RichTextRenderer, { node: doc }))const reader = stream.getReader()
A reader has a read()
method which returns a Promise that resolves to the next value received from the stream. There is one problem, the value is received as Uint8Array and so we will need to decode it with a TextDecoder
.
const { value, done } = await reader.read()if (value) {html += new TextDecoder().decode(value)}
We can use this within a loop to read until the stream is finished. Here is the final result.
import ReactDOMServer from 'react-dom/server'import { createElement } from 'react'import type { RemirrorJSON } from 'remirror'import { RichTextRenderer } from './src/RichTextRenderer'export { isRemirrorJSON } from 'remirror'export async function generateHTMLFromDoc(doc: RemirrorJSON) {const stream = await ReactDOMServer.renderToReadableStream(createElement(RichTextRenderer, { node: doc }))const reader = stream.getReader()let html = ''while (true) {const { value, done } = await reader.read()if (value) {html += new TextDecoder().decode(value)}if (done) {return html}}}