diff --git a/.changeset/yellow-hounds-jog.md b/.changeset/yellow-hounds-jog.md new file mode 100644 index 0000000..2b3b40a --- /dev/null +++ b/.changeset/yellow-hounds-jog.md @@ -0,0 +1,5 @@ +--- +'preact-render-to-string': patch +--- + +Only abort/report errors from `renderToPipeableStream()` if the stream hasn't already been closed diff --git a/src/stream-node.js b/src/stream-node.js index bffa20e..e39da31 100644 --- a/src/stream-node.js +++ b/src/stream-node.js @@ -60,7 +60,14 @@ export function renderToPipeableStream(vnode, options, context) { /** * @param {unknown} [reason] */ - abort(reason = new Error('The render was aborted by the server without a reason.')) { + abort( + reason = new Error( + 'The render was aborted by the server without a reason.' + ) + ) { + // Remix/React-Router will always call abort after a timeout, even on success + if (stream.closed) return; + controller.abort(); stream.destroy(); if (options.onError) { diff --git a/test/compat/stream-node.test.js b/test/compat/stream-node.test.js index 5783887..159e0e2 100644 --- a/test/compat/stream-node.test.js +++ b/test/compat/stream-node.test.js @@ -73,4 +73,19 @@ describe('renderToPipeableStream', () => { '' ]); }); + + it('should not error if the stream has already been closed', async () => { + let error; + const sink = createSink(); + const { pipe, abort } = renderToPipeableStream(
it works
'), + createSubtree('56', 'it works
'), '