Skip to content

Commit b4477d3

Browse files
authored
[Flight] Add a cached 3rd-party component to the Flight fixture (facebook#33443)
This should allow us to visualize what facebook#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 facebook#33438.
1 parent 93f1668 commit b4477d3

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

fixtures/flight/src/App.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
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';
25

36
import Container from './Container.js';
47

@@ -35,8 +38,50 @@ async function Bar({children}) {
3538
return <div>{children}</div>;
3639
}
3740

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+
3882
async function ServerComponent() {
3983
await new Promise(resolve => setTimeout(() => resolve('deferred text'), 50));
84+
return await fetchThirdParty();
4085
}
4186

4287
export default async function App({prerender}) {

0 commit comments

Comments
 (0)