Skip to content

renderToPipeableStream in server.js Does Not Wait for Async Content Inside Suspense #40

Description

@welkinwong

The renderToString method in server.js converts the stream returned by renderToPipeableStream into a string. However, during testing, it was observed that onAllReady is triggered and toString() is called before the stream fully completes, meaning it does not wait for asynchronous content inside Suspense boundaries.

Issue:

  • onAllReady fires once the initial shell (non-Suspense content) is rendered, but does not wait for Suspense-bound async components to resolve.
  • This can lead to incomplete HTML if toString() is called prematurely.
=> Meteor server restarted at: http://localhost:3000/
I20250423-16:02:43.723(8)? onShellReady
I20250423-16:02:43.723(8)? --- Chunk 1 ---
I20250423-16:02:43.724(8)? <div class="max-w-3xl min-h-screen mx-auto sm:pt-10"><h1 class="text-center text-5xl font-extrabold">Meteor Community Packages</h1><h1 class="text-center text-8xl font-extrabold">SSR Demo</h1>ddd<!--$?--><template id="B:0"></template><div>Loading...</div><!--/$--></div><script>window.__staticRouterHydrationData = JSON.parse("{\"loaderData\":{\"0\":null},\"actionData\":null,\"errors\":null}");</script>
I20250423-16:02:43.724(8)? --- Chunk 2 ---
I20250423-16:02:43.724(8)? <div hidden id="S:0"><div class="bg-white shadow sm:rounded-lg mb-4"><div class="px-4 py-5 sm:p-6"><div class="sm:flex sm:items-start sm:justify-between"><div><div class="flex items-center"><h3 class="text-3xl text-gray-900 font-bold">Welcome to the React SSR Demo!</h3><div><svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 400 400"><g fill="#DE4F4F"><path d="
I20250423-16:02:43.724(8)? --- Chunk 3 ---
I20250423-16:02:43.724(8)? M286.575 306.886L44.755 49.922l256.962 241.82c4.312 4.056 4.518 10.837.46 15.146-4.053 4.31-10.832 4.518-15.144.46-.15-.14-.318-.31-.458-.462M251.032 325.01L68.692 127.528 266.177 309.87c4.35 4.013 4.618 10.794.604 15.144-4.018 4.35-10.794 4.617-15.146.604-.2-.19-.413-.406-.602-.607M214.083 325.542L92.907 194.272 224.18 315.446c2.898 2.676 3.077 7.197.402 10.098-2.677 2.896-7.195 3.082-10.097.402-.136-.125-.277-.272-.402-.405M315.612 234.685L189.102 98.078 325.71 224.585c2.896 2.684 3.067 7.203.387 10.1-2.682 2.895-7.2 3.066-10.098.387-.13-.123-.268-.258-.388-.387M304.697 272.93L121.567 74.655l198.274 183.13c4.35 4.017 4.62 10.796.605 15.144-4.017 4.352-10.797 4.617-15.146.604-.205-.19-.418-.404-.603-.605M176.31 314.783l-57.647-62.695 62.692 57.65c1.453 1.334 1.547 3.596.215 5.045-1.338 1.453-3.598 1.55-5.05.215-.072-.07-.144-.143-.21-.215M311.093 189.297l-57.65-62.694 62.696 57.646c1.45 1.335 1.546 3.597.21 5.048-1.335 1.45-3.595 1.547-5.05.21-.07-.065-.143-.143-.207-.21
I20250423-16:02:43.724(8)? --- Chunk 4 ---
I20250423-16:02:43.724(8)? "></path></g></svg></div></div><div class="mt-2 max-w-xl text-gray-500 text-lg"><p>You&#x27;ve pressed the button <b>0</b> times.</p></div></div><div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center"><button type="button" class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 text-lg">Click Me</button></div></div></div></div><template id="P:1"></template></div>
I20250423-16:02:43.728(8)? onAllReady <div class="max-w-3xl min-h-screen mx-auto sm:pt-10"><h1 class="text-center text-5xl font-extrabold">Meteor Community Packages</h1><h1 class="text-center text-8xl font-extrabold">SSR Demo</h1>ddd<!--$?--><template id="B:0"></template><div>Loading...</div><!--/$--></div><script>window.__staticRouterHydrationData = JSON.parse("{\"loaderData\":{\"0\":null},\"actionData\":null,\"errors\":null}");</script><div hidden id="S:0"><div class="bg-white shadow sm:rounded-lg mb-4"><div class="px-4 py-5 sm:p-6"><div class="sm:flex sm:items-start sm:justify-between"><div><div class="flex items-center"><h3 class="text-3xl text-gray-900 font-bold">Welcome to the React SSR Demo!</h3><div><svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 400 400"><g fill="#DE4F4F"><path d="M286.575 306.886L44.755 49.922l256.962 241.82c4.312 4.056 4.518 10.837.46 15.146-4.053 4.31-10.832 4.518-15.144.46-.15-.14-.318-.31-.458-.462M251.032 325.01L68.692 127.528 266.177 309.87c4.35 4.013 4.618 10.794.604 15.144-4.018 4.35-10.794 4.617-15.146.604-.2-.19-.413-.406-.602-.607M214.083 325.542L92.907 194.272 224.18 315.446c2.898 2.676 3.077 7.197.402 10.098-2.677 2.896-7.195 3.082-10.097.402-.136-.125-.277-.272-.402-.405M315.612 234.685L189.102 98.078 325.71 224.585c2.896 2.684 3.067 7.203.387 10.1-2.682 2.895-7.2 3.066-10.098.387-.13-.123-.268-.258-.388-.387M304.697 272.93L121.567 74.655l198.274 183.13c4.35 4.017 4.62 10.796.605 15.144-4.017 4.352-10.797 4.617-15.146.604-.205-.19-.418-.404-.603-.605M176.31 314.783l-57.647-62.695 62.692 57.65c1.453 1.334 1.547 3.596.215 5.045-1.338 1.453-3.598 1.55-5.05.215-.072-.07-.144-.143-.21-.215M311.093 189.297l-57.65-62.694 62.696 57.646c1.45 1.335 1.546 3.597.21 5.048-1.335 1.45-3.595 1.547-5.05.21-.07-.065-.143-.143-.207-.21"></path></g></svg></div></div><div class="mt-2 max-w-xl text-gray-500 text-lg"><p>You&#x27;ve pressed the button <b>0</b> times.</p></div></div><div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center"><button type="button" class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 text-lg">Click Me</button></div></div></div></div><template id="P:1"></template></div>
I20250423-16:02:43.728(8)? --- Chunk 5 ---
I20250423-16:02:43.728(8)? <div hidden id="S:1">asdf</div><script>$RS=function(a,b){a=document.getElementById(a);b=document.getElementById(b);for(a.parentNode.removeChild(a);a.firstChild;)b.parentNode.insertBefore(a.firstChild,b);b.parentNode.removeChild(b)};$RS("S:1","P:1")</script><script>$RC=function(b,c,e){c=document.getElementById(c);c.parentNode.removeChild(c);var a=document.getElementById(b);if(a){b=a.previousSibling;if(e)b.data="$!",a.setAttribute("data-dgst",e);else{e=b.parentNode;a=b.nextSibling;var f=0;do{if(a&&8===a.nodeType){var d=a.data;if("/$"===d)if(0===f)break;else f--;else"$"!==d&&"$?"!==d&&"$!"!==d||f++}d=a.nextSibling;e.removeChild(a);a=d}while(a);for(;c.firstChild;)e.insertBefore(c.firstChild,a);b.data="$"}b._reactRetry&&b._reactRetry()}};$RC("B:0","S:0")</script>
I20250423-16:02:43.728(8)? --- Stream ended ---

Reproduction Steps:

In this project: https://github.com/copleykj/react-router-ssr-demo
upgrade react-meteor-data to react-meteor-data@3.0.5-beta.0, and the issue can be observed.

PS: I used a loggerStream to log chunk information for debugging.

let chunkCount = 0;

const loggerStream = new Transform({
  transform(chunk, encoding, callback) {
    chunkCount++;
    console.log(`--- Chunk ${chunkCount} ---`);
    console.log(chunk.toString());
    this.push(chunk);
    callback();
  },
  flush(callback) {
    console.log('--- Stream ended ---');
    callback();
  }
});

In the forums, users reported a failure in react-meteor-data@3.0.5-beta.0
https://forums.meteor.com/t/communitypackages-react-router-ssr-v6-beta-release/63418/3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions