@samitouri / QOS-React / commits / b4477d3800

[Flight] Add a cached 3rd-party component to the Flight fixture (#33443)

This should allow us to visualize what https://github.com/facebook/react/pull/33438 is trying to convey. An uncached 3rd-party component is displayed like this in the dev tools: <img width="1072" alt="Screenshot 2025-06-05 at 12 57 32" src="https://github.com/user-attachments/assets/d418ae23-d113-4dc9-98b8-ab426710454a" /> However, when the component is restored from a cache, it looks like this: <img width="1072" alt="Screenshot 2025-06-05 at 12 56 56" src="https://github.com/user-attachments/assets/a0e34379-d8c0-4b14-8b54-b5c06211232b" /> The `Server Components ⚛` track is missing completely here, and the `Loading profile...` phase also took way longer than without caching the 3rd-party component. On `main`, the `Server Components ⚛` track is not missing: <img width="1072" alt="Screenshot 2025-06-05 at 14 31 20" src="https://github.com/user-attachments/assets/c35e405d-27ca-4b04-a34c-03bd959a7687" /> The cached 3rd-party component starts before the current render, and is also not excluded here, which is of course expected without #33438.

Hendrik Liebau committed Jun 5, 2025 at 17:19 UTC b4477d3800ccb0bdf26670cd1f021d094159c38f
1 file changed +45
fixtures/flight/src/App.js
+45
@@ -1,4 +1,7 @@
1 import * as React from 'react';
2 +import {renderToPipeableStream} from 'react-server-dom-webpack/server';
3 +import {createFromNodeStream} from 'react-server-dom-webpack/client';
4 +import {PassThrough, Readable} from 'stream';
5
6 import Container from './Container.js';
7
@@ -35,8 +38,50 @@ async function Bar({children}) {
38 return <div>{children}</div>;
39 }
40
41 +async function ThirdPartyComponent() {
42 + return new Promise(resolve =>
43 + setTimeout(() => resolve('hello from a 3rd party'), 30)
44 + );
45 +}
46 +
47 +// Using Web streams for tee'ing convenience here.
48 +let cachedThirdPartyReadableWeb;
49 +
50 +function fetchThirdParty(Component) {
51 + if (cachedThirdPartyReadableWeb) {
52 + const [readableWeb1, readableWeb2] = cachedThirdPartyReadableWeb.tee();
53 + cachedThirdPartyReadableWeb = readableWeb1;
54 +
55 + return createFromNodeStream(Readable.fromWeb(readableWeb2), {
56 + moduleMap: {},
57 + moduleLoading: {},
58 + });
59 + }
60 +
61 + const stream = renderToPipeableStream(
62 + <ThirdPartyComponent />,
63 + {},
64 + {environmentName: 'third-party'}
65 + );
66 +
67 + const readable = new PassThrough();
68 + // React currently only supports piping to one stream, so we convert, tee, and
69 + // convert back again.
70 + // TODO: Switch to web streams without converting when #33442 has landed.
71 + const [readableWeb1, readableWeb2] = Readable.toWeb(readable).tee();
72 + cachedThirdPartyReadableWeb = readableWeb1;
73 + const result = createFromNodeStream(Readable.fromWeb(readableWeb2), {
74 + moduleMap: {},
75 + moduleLoading: {},
76 + });
77 + stream.pipe(readable);
78 +
79 + return result;
80 +}
81 +
82 async function ServerComponent() {
83 await new Promise(resolve => setTimeout(() => resolve('deferred text'), 50));
84 + return await fetchThirdParty();
85 }
86
87 export default async function App({prerender}) {