@samitouri / QOS-React / commits / b1759882c0

[Flight] Bypass caches in Flight fixture if requested (#33445)

Hendrik Liebau committed Jun 6, 2025 at 06:42 UTC b1759882c0b8045aff27fa9e41600534d396f69c
3 files changed +21 -15
fixtures/flight/server/global.js
+3
@@ -101,6 +101,9 @@ async function renderApp(req, res, next) {
101 } else if (req.get('Content-type')) {
102 proxiedHeaders['Content-type'] = req.get('Content-type');
103 }
104 + if (req.headers['cache-control']) {
105 + proxiedHeaders['Cache-Control'] = req.get('cache-control');
106 + }
107
108 const requestsPrerender = req.path === '/prerender';
109
fixtures/flight/server/region.js
+12 -9
@@ -50,7 +50,7 @@ const {readFile} = require('fs').promises;
50
51 const React = require('react');
52
53 -async function renderApp(res, returnValue, formState) {
53 +async function renderApp(res, returnValue, formState, noCache) {
54 const {renderToPipeableStream} = await import(
55 'react-server-dom-webpack/server'
56 );
@@ -97,7 +97,7 @@ async function renderApp(res, returnValue, formState) {
97 key: filename,
98 })
99 ),
100 - React.createElement(App)
100 + React.createElement(App, {noCache})
101 );
102 // For client-invoked server actions we refresh the tree and return a return value.
103 const payload = {root, returnValue, formState};
@@ -105,7 +105,7 @@ async function renderApp(res, returnValue, formState) {
105 pipe(res);
106 }
107
108 -async function prerenderApp(res, returnValue, formState) {
108 +async function prerenderApp(res, returnValue, formState, noCache) {
109 const {unstable_prerenderToNodeStream: prerenderToNodeStream} = await import(
110 'react-server-dom-webpack/static'
111 );
@@ -152,7 +152,7 @@ async function prerenderApp(res, returnValue, formState) {
152 key: filename,
153 })
154 ),
155 - React.createElement(App, {prerender: true})
155 + React.createElement(App, {prerender: true, noCache})
156 );
157 // For client-invoked server actions we refresh the tree and return a return value.
158 const payload = {root, returnValue, formState};
@@ -161,14 +161,17 @@ async function prerenderApp(res, returnValue, formState) {
161 }
162
163 app.get('/', async function (req, res) {
164 + const noCache = req.get('cache-control') === 'no-cache';
165 +
166 if ('prerender' in req.query) {
165 - await prerenderApp(res, null, null);
167 + await prerenderApp(res, null, null, noCache);
168 } else {
167 - await renderApp(res, null, null);
169 + await renderApp(res, null, null, noCache);
170 }
171 });
172
173 app.post('/', bodyParser.text(), async function (req, res) {
174 + const noCache = req.headers['cache-control'] === 'no-cache';
175 const {decodeReply, decodeReplyFromBusboy, decodeAction, decodeFormState} =
176 await import('react-server-dom-webpack/server');
177 const serverReference = req.get('rsc-action');
@@ -201,7 +204,7 @@ app.post('/', bodyParser.text(), async function (req, res) {
204 // We handle the error on the client
205 }
206 // Refresh the client and return the value
204 - renderApp(res, result, null);
207 + renderApp(res, result, null, noCache);
208 } else {
209 // This is the progressive enhancement case
210 const UndiciRequest = require('undici').Request;
@@ -217,11 +220,11 @@ app.post('/', bodyParser.text(), async function (req, res) {
220 // Wait for any mutations
221 const result = await action();
222 const formState = decodeFormState(result, formData);
220 - renderApp(res, null, formState);
223 + renderApp(res, null, formState, noCache);
224 } catch (x) {
225 const {setServerState} = await import('../src/ServerState.js');
226 setServerState('Error: ' + x.message);
224 - renderApp(res, null, null);
227 + renderApp(res, null, null, noCache);
228 }
229 }
230 });
fixtures/flight/src/App.js
+6 -6
@@ -47,8 +47,8 @@ async function ThirdPartyComponent() {
47 // Using Web streams for tee'ing convenience here.
48 let cachedThirdPartyReadableWeb;
49
50 -function fetchThirdParty(Component) {
51 - if (cachedThirdPartyReadableWeb) {
50 +function fetchThirdParty(noCache) {
51 + if (cachedThirdPartyReadableWeb && !noCache) {
52 const [readableWeb1, readableWeb2] = cachedThirdPartyReadableWeb.tee();
53 cachedThirdPartyReadableWeb = readableWeb1;
54
@@ -79,16 +79,16 @@ function fetchThirdParty(Component) {
79 return result;
80 }
81
82 -async function ServerComponent() {
82 +async function ServerComponent({noCache}) {
83 await new Promise(resolve => setTimeout(() => resolve('deferred text'), 50));
84 - return await fetchThirdParty();
84 + return fetchThirdParty(noCache);
85 }
86
87 -export default async function App({prerender}) {
87 +export default async function App({prerender, noCache}) {
88 const res = await fetch('http://localhost:3001/todos');
89 const todos = await res.json();
90
91 - const dedupedChild = <ServerComponent />;
91 + const dedupedChild = <ServerComponent noCache={noCache} />;
92 const message = getServerState();
93 return (
94 <html lang="en">