Skip to content

Commit 753b087

Browse files
committed
stream-node: dedupe abort errors and preserve abort reasons
1 parent 5702db5 commit 753b087

2 files changed

Lines changed: 28 additions & 6 deletions

File tree

src/stream-node.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ export function renderToPipeableStream(vnode, options, context) {
2626
const controller = new AbortController();
2727
const stream = new PassThrough();
2828
let waitingForDrain = null;
29+
let aborted = false;
2930
let shellReadyCalled = false;
3031
let allReadyCalled = false;
3132
let errored = false;
3233
let shellReadyScheduled = false;
34+
stream.on('error', () => {});
3335

3436
function callOnShellReady() {
3537
if (shellReadyCalled || errored) return;
@@ -127,13 +129,19 @@ export function renderToPipeableStream(vnode, options, context) {
127129
)
128130
) {
129131
// Remix/React-Router will always call abort after a timeout, even on success
130-
if (stream.closed) return;
131-
132-
controller.abort();
133-
stream.destroy();
134-
if (options.onError) {
135-
options.onError(reason);
132+
if (
133+
aborted ||
134+
stream.closed ||
135+
stream.destroyed ||
136+
stream.writableEnded
137+
) {
138+
return;
136139
}
140+
141+
aborted = true;
142+
controller.abort(reason);
143+
stream.destroy(reason);
144+
callOnError(reason);
137145
},
138146
/**
139147
* @param {import("stream").Writable} writable

test/compat/stream-node.test.jsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,18 @@ describe('renderToPipeableStream', () => {
112112
expect(caught).toBeInstanceOf(Error);
113113
expect(caught.message).toBe('shell failed');
114114
});
115+
116+
it('should only call onError once for repeated aborts', async () => {
117+
const errors = [];
118+
const { abort } = renderToPipeableStream(<div class="foo">bar</div>, {
119+
onError: (error) => errors.push(error)
120+
});
121+
122+
const first = new Error('first abort');
123+
abort(first);
124+
abort(new Error('second abort'));
125+
126+
expect(errors).toHaveLength(1);
127+
expect(errors[0]).toBe(first);
128+
});
115129
});

0 commit comments

Comments
 (0)