From 24dbf7c5e4cf2c75c5fe892bce342841db6fc203 Mon Sep 17 00:00:00 2001 From: f0x Date: Thu, 16 Jan 2025 17:15:22 +0100 Subject: [PATCH 1/3] add failing test for three suspended direct children withing a suspense boundary that resolve one-after-another --- test/compat/async.test.jsx | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/compat/async.test.jsx b/test/compat/async.test.jsx index 0ca7835..62a347d 100644 --- a/test/compat/async.test.jsx +++ b/test/compat/async.test.jsx @@ -254,6 +254,48 @@ describe('Async renderToString', () => { expect(rendered).to.equal(expected); }); + it('should render JSX with multiple suspended direct children within a single suspense boundary that resolve one-after-another', async () => { + const { + Suspender: SuspenderOne, + suspended: suspendedOne + } = createSuspender(); + const { + Suspender: SuspenderTwo, + suspended: suspendedTwo + } = createSuspender(); + const { + Suspender: SuspenderThree, + suspended: suspendedThree + } = createSuspender(); + + const promise = renderToStringAsync( + + ); + + const expected = ``; + + suspendedOne.promise.then(() => { void suspendedTwo.resolve();}); + suspendedTwo.promise.then(() => { void suspendedThree.resolve();}); + + suspendedOne.resolve(); + + const rendered = await promise; + + expect(rendered).to.equal(expected); + }); + it('should rethrow error thrown after suspending', async () => { const { suspended, getResolved } = createSuspender(); From 44d450507575a55ead42abf18a65a4381d148621 Mon Sep 17 00:00:00 2001 From: f0x Date: Thu, 16 Jan 2025 17:37:58 +0100 Subject: [PATCH 2/3] correct recursive rendering of thrown promises in async renders --- src/index.js | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/index.js b/src/index.js index f6530f4..9c69683 100644 --- a/src/index.js +++ b/src/index.js @@ -542,21 +542,8 @@ function _renderToString( : result; } catch (e) { if (!e || typeof e.then != 'function') throw e; - - return e.then(() => { - const result = _renderToString( - rendered, - context, - isSvgMode, - selectValue, - vnode, - asyncMode, - renderer - ); - return vnode._suspended - ? BEGIN_SUSPENSE_DENOMINATOR + result + END_SUSPENSE_DENOMINATOR - : result; - }, renderNestedChildren); + + return e.then(renderNestedChildren); } }; From b87bea99dcb3e50f726cd78ff2f90d999242b758 Mon Sep 17 00:00:00 2001 From: f0x Date: Thu, 16 Jan 2025 18:02:49 +0100 Subject: [PATCH 3/3] add changeset --- .changeset/long-ties-brake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/long-ties-brake.md diff --git a/.changeset/long-ties-brake.md b/.changeset/long-ties-brake.md new file mode 100644 index 0000000..333694f --- /dev/null +++ b/.changeset/long-ties-brake.md @@ -0,0 +1,5 @@ +--- +'preact-render-to-string': patch +--- + +Fix async rendering of multiple suspended components in a single Suspense boundary