diff options
Diffstat (limited to 'packages/integrations/react/server.js')
-rw-r--r-- | packages/integrations/react/server.js | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/packages/integrations/react/server.js b/packages/integrations/react/server.js index 6ae49e7bc..b41492a7a 100644 --- a/packages/integrations/react/server.js +++ b/packages/integrations/react/server.js @@ -12,7 +12,7 @@ function errorIsComingFromPreactComponent(err) { ); } -function check(Component, props, children) { +async function check(Component, props, children) { // Note: there are packages that do some unholy things to create "components". // Checking the $$typeof property catches most of these patterns. if (typeof Component === 'object') { @@ -42,7 +42,7 @@ function check(Component, props, children) { return React.createElement('div'); } - renderToStaticMarkup(Tester, props, children, {}); + await renderToStaticMarkup(Tester, props, children, {}); if (error) { throw error; @@ -50,7 +50,13 @@ function check(Component, props, children) { return isReactComponent; } -function renderToStaticMarkup(Component, props, children, metadata) { +async function getNodeWritable() { + let nodeStreamBuiltinModuleName = 'stream'; + let { Writable } = await import(nodeStreamBuiltinModuleName); + return Writable; +} + +async function renderToStaticMarkup(Component, props, children, metadata) { delete props['class']; const vnode = React.createElement(Component, { ...props, @@ -59,12 +65,74 @@ function renderToStaticMarkup(Component, props, children, metadata) { let html; if (metadata && metadata.hydrate) { html = ReactDOM.renderToString(vnode); + if('renderToReadableStream' in ReactDOM) { + html = await renderToReadableStreamAsync(vnode); + } else { + html = await renderToPipeableStreamAsync(vnode); + } } else { - html = ReactDOM.renderToStaticMarkup(vnode); + if('renderToReadableStream' in ReactDOM) { + html = await renderToReadableStreamAsync(vnode); + } else { + html = await renderToStaticNodeStreamAsync(vnode); + } + } return { html }; } +async function renderToPipeableStreamAsync(vnode) { + const Writable = await getNodeWritable(); + let html = ''; + return new Promise((resolve, reject) => { + let error = undefined; + let stream = ReactDOM.renderToPipeableStream(vnode, { + onError(err) { + error = err; + reject(error); + }, + onAllReady() { + stream.pipe(new Writable({ + write(chunk, _encoding, callback) { + html += chunk.toString('utf-8'); + callback(); + }, + destroy() { + resolve(html); + } + })); + } + }); + }); +} + +async function renderToStaticNodeStreamAsync(vnode) { + const Writable = await getNodeWritable(); + let html = ''; + return new Promise((resolve) => { + let stream = ReactDOM.renderToStaticNodeStream(vnode); + stream.pipe(new Writable({ + write(chunk, _encoding, callback) { + html += chunk.toString('utf-8'); + callback(); + }, + destroy() { + resolve(html); + } + })); + }); +} + +async function renderToReadableStreamAsync(vnode) { + const decoder = new TextDecoder(); + const stream = await ReactDOM.renderToReadableStream(vnode); + let html = ''; + for await(const chunk of stream) { + html += decoder.decode(chunk); + } + return html; +} + export default { check, renderToStaticMarkup, |