Skip to content

Commit f1e6f39

Browse files
committed
[Flight] Preload <img> and <link> using hints before they're rendered (facebook#34604)
In Fizz and Fiber we emit hints for suspensey images and CSS as soon as we discover them during render. At the beginning of the stream. This adds a similar capability when a Host Component is known to be a Host Component during the Flight render. The client doesn't know that these resources are in the payload until it parses that particular component which is lazy. So they need to be hoisted with hints. We detect when these are rendered during Flight and add them as hints. That allows you to consume a Flight payload to preload prefetched content without having to render it. `<link rel="preload">` can be hoisted more or less as is. `<link rel="stylesheet">` we preload but we don't actually insert them anywhere until they're rendered. We do these even for non-suspensey stylesheets since we know that when they're rendered they're going to start loading even if they're not immediately used. They're never lazy. `<img src>` we only preload if they follow the suspensey image pattern since otherwise they may be more lazy e.g. by if they're in the viewport. We also skip if they're known to be inside `<picture>`. Same as Fizz. Ideally this would preload the other `<source>` but it's tricky. The downside of this is that you might conditionally render something in only one branch given a client component. However, in that case you're already eagerly fetching the server component's data in that branch so it's not too much of a stretch that you want to eagerly fetch the corresponding resources as well. If you wanted it to be lazy, you should've done a lazy fetch of the RSC. We don't collect hints when any of these are wrapped in a Client Component. In those cases you might want to add your own preload to a wrapper Shared Component. Everything is skipped if it's known to be inside `<noscript>`. Note that the format context is approximate (see facebook#34601) so it's possible for these hints to overfetch or underfetch if you try to trick it. E.g. by rendering Server Components inside a Client Component that renders `<noscript>`. --------- Co-authored-by: Josh Story <josh.c.story@gmail.com> DiffTrain build for [047715c](facebook@047715c)
1 parent 5ba064c commit f1e6f39

34 files changed

+114
-296
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
df38ac9a3b9a5ea43c1d07c00d090a448acfd56c
1+
047715c4ba0922ae3cd34bc9f1c1895e67ae3faa
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
df38ac9a3b9a5ea43c1d07c00d090a448acfd56c
1+
047715c4ba0922ae3cd34bc9f1c1895e67ae3faa

compiled/facebook-www/React-dev.classic.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,6 @@ __DEV__ &&
586586
function useMemoCache(size) {
587587
return resolveDispatcher().useMemoCache(size);
588588
}
589-
function useEffectEvent(callback) {
590-
return resolveDispatcher().useEffectEvent(callback);
591-
}
592589
function releaseAsyncTransition() {
593590
ReactSharedInternals.asyncTransitions--;
594591
}
@@ -1199,7 +1196,9 @@ __DEV__ &&
11991196
Object.seal(refObject);
12001197
return refObject;
12011198
};
1202-
exports.experimental_useEffectEvent = useEffectEvent;
1199+
exports.experimental_useEffectEvent = function (callback) {
1200+
return resolveDispatcher().useEffectEvent(callback);
1201+
};
12031202
exports.forwardRef = function (render) {
12041203
null != render && render.$$typeof === REACT_MEMO_TYPE
12051204
? console.error(
@@ -1371,7 +1370,6 @@ __DEV__ &&
13711370
);
13721371
return resolveDispatcher().useEffect(create, deps);
13731372
};
1374-
exports.useEffectEvent = useEffectEvent;
13751373
exports.useId = function () {
13761374
return resolveDispatcher().useId();
13771375
};
@@ -1421,7 +1419,7 @@ __DEV__ &&
14211419
exports.useTransition = function () {
14221420
return resolveDispatcher().useTransition();
14231421
};
1424-
exports.version = "19.2.0-www-classic-df38ac9a-20250926";
1422+
exports.version = "19.2.0-www-classic-047715c4-20250925";
14251423
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14261424
"function" ===
14271425
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,6 @@ __DEV__ &&
586586
function useMemoCache(size) {
587587
return resolveDispatcher().useMemoCache(size);
588588
}
589-
function useEffectEvent(callback) {
590-
return resolveDispatcher().useEffectEvent(callback);
591-
}
592589
function releaseAsyncTransition() {
593590
ReactSharedInternals.asyncTransitions--;
594591
}
@@ -1199,7 +1196,9 @@ __DEV__ &&
11991196
Object.seal(refObject);
12001197
return refObject;
12011198
};
1202-
exports.experimental_useEffectEvent = useEffectEvent;
1199+
exports.experimental_useEffectEvent = function (callback) {
1200+
return resolveDispatcher().useEffectEvent(callback);
1201+
};
12031202
exports.forwardRef = function (render) {
12041203
null != render && render.$$typeof === REACT_MEMO_TYPE
12051204
? console.error(
@@ -1371,7 +1370,6 @@ __DEV__ &&
13711370
);
13721371
return resolveDispatcher().useEffect(create, deps);
13731372
};
1374-
exports.useEffectEvent = useEffectEvent;
13751373
exports.useId = function () {
13761374
return resolveDispatcher().useId();
13771375
};
@@ -1421,7 +1419,7 @@ __DEV__ &&
14211419
exports.useTransition = function () {
14221420
return resolveDispatcher().useTransition();
14231421
};
1424-
exports.version = "19.2.0-www-modern-df38ac9a-20250926";
1422+
exports.version = "19.2.0-www-modern-047715c4-20250925";
14251423
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
14261424
"function" ===
14271425
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,6 @@ function lazyInitializer(payload) {
308308
function useMemoCache(size) {
309309
return ReactSharedInternals.H.useMemoCache(size);
310310
}
311-
function useEffectEvent(callback) {
312-
return ReactSharedInternals.H.useEffectEvent(callback);
313-
}
314311
var reportGlobalError =
315312
"function" === typeof reportError
316313
? reportError
@@ -505,7 +502,9 @@ exports.createElement = function (type, config, children) {
505502
exports.createRef = function () {
506503
return { current: null };
507504
};
508-
exports.experimental_useEffectEvent = useEffectEvent;
505+
exports.experimental_useEffectEvent = function (callback) {
506+
return ReactSharedInternals.H.useEffectEvent(callback);
507+
};
509508
exports.forwardRef = function (render) {
510509
return { $$typeof: REACT_FORWARD_REF_TYPE, render: render };
511510
};
@@ -562,7 +561,6 @@ exports.useDeferredValue = function (value, initialValue) {
562561
exports.useEffect = function (create, deps) {
563562
return ReactSharedInternals.H.useEffect(create, deps);
564563
};
565-
exports.useEffectEvent = useEffectEvent;
566564
exports.useId = function () {
567565
return ReactSharedInternals.H.useId();
568566
};
@@ -604,4 +602,4 @@ exports.useSyncExternalStore = function (
604602
exports.useTransition = function () {
605603
return ReactSharedInternals.H.useTransition();
606604
};
607-
exports.version = "19.2.0-www-classic-df38ac9a-20250926";
605+
exports.version = "19.2.0-www-classic-047715c4-20250925";

compiled/facebook-www/React-prod.modern.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,6 @@ function lazyInitializer(payload) {
308308
function useMemoCache(size) {
309309
return ReactSharedInternals.H.useMemoCache(size);
310310
}
311-
function useEffectEvent(callback) {
312-
return ReactSharedInternals.H.useEffectEvent(callback);
313-
}
314311
var reportGlobalError =
315312
"function" === typeof reportError
316313
? reportError
@@ -505,7 +502,9 @@ exports.createElement = function (type, config, children) {
505502
exports.createRef = function () {
506503
return { current: null };
507504
};
508-
exports.experimental_useEffectEvent = useEffectEvent;
505+
exports.experimental_useEffectEvent = function (callback) {
506+
return ReactSharedInternals.H.useEffectEvent(callback);
507+
};
509508
exports.forwardRef = function (render) {
510509
return { $$typeof: REACT_FORWARD_REF_TYPE, render: render };
511510
};
@@ -562,7 +561,6 @@ exports.useDeferredValue = function (value, initialValue) {
562561
exports.useEffect = function (create, deps) {
563562
return ReactSharedInternals.H.useEffect(create, deps);
564563
};
565-
exports.useEffectEvent = useEffectEvent;
566564
exports.useId = function () {
567565
return ReactSharedInternals.H.useId();
568566
};
@@ -604,4 +602,4 @@ exports.useSyncExternalStore = function (
604602
exports.useTransition = function () {
605603
return ReactSharedInternals.H.useTransition();
606604
};
607-
exports.version = "19.2.0-www-modern-df38ac9a-20250926";
605+
exports.version = "19.2.0-www-modern-047715c4-20250925";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,6 @@ function lazyInitializer(payload) {
312312
function useMemoCache(size) {
313313
return ReactSharedInternals.H.useMemoCache(size);
314314
}
315-
function useEffectEvent(callback) {
316-
return ReactSharedInternals.H.useEffectEvent(callback);
317-
}
318315
var reportGlobalError =
319316
"function" === typeof reportError
320317
? reportError
@@ -509,7 +506,9 @@ exports.createElement = function (type, config, children) {
509506
exports.createRef = function () {
510507
return { current: null };
511508
};
512-
exports.experimental_useEffectEvent = useEffectEvent;
509+
exports.experimental_useEffectEvent = function (callback) {
510+
return ReactSharedInternals.H.useEffectEvent(callback);
511+
};
513512
exports.forwardRef = function (render) {
514513
return { $$typeof: REACT_FORWARD_REF_TYPE, render: render };
515514
};
@@ -566,7 +565,6 @@ exports.useDeferredValue = function (value, initialValue) {
566565
exports.useEffect = function (create, deps) {
567566
return ReactSharedInternals.H.useEffect(create, deps);
568567
};
569-
exports.useEffectEvent = useEffectEvent;
570568
exports.useId = function () {
571569
return ReactSharedInternals.H.useId();
572570
};
@@ -608,7 +606,7 @@ exports.useSyncExternalStore = function (
608606
exports.useTransition = function () {
609607
return ReactSharedInternals.H.useTransition();
610608
};
611-
exports.version = "19.2.0-www-classic-df38ac9a-20250926";
609+
exports.version = "19.2.0-www-classic-047715c4-20250925";
612610
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
613611
"function" ===
614612
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,6 @@ function lazyInitializer(payload) {
312312
function useMemoCache(size) {
313313
return ReactSharedInternals.H.useMemoCache(size);
314314
}
315-
function useEffectEvent(callback) {
316-
return ReactSharedInternals.H.useEffectEvent(callback);
317-
}
318315
var reportGlobalError =
319316
"function" === typeof reportError
320317
? reportError
@@ -509,7 +506,9 @@ exports.createElement = function (type, config, children) {
509506
exports.createRef = function () {
510507
return { current: null };
511508
};
512-
exports.experimental_useEffectEvent = useEffectEvent;
509+
exports.experimental_useEffectEvent = function (callback) {
510+
return ReactSharedInternals.H.useEffectEvent(callback);
511+
};
513512
exports.forwardRef = function (render) {
514513
return { $$typeof: REACT_FORWARD_REF_TYPE, render: render };
515514
};
@@ -566,7 +565,6 @@ exports.useDeferredValue = function (value, initialValue) {
566565
exports.useEffect = function (create, deps) {
567566
return ReactSharedInternals.H.useEffect(create, deps);
568567
};
569-
exports.useEffectEvent = useEffectEvent;
570568
exports.useId = function () {
571569
return ReactSharedInternals.H.useId();
572570
};
@@ -608,7 +606,7 @@ exports.useSyncExternalStore = function (
608606
exports.useTransition = function () {
609607
return ReactSharedInternals.H.useTransition();
610608
};
611-
exports.version = "19.2.0-www-modern-df38ac9a-20250926";
609+
exports.version = "19.2.0-www-modern-047715c4-20250925";
612610
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
613611
"function" ===
614612
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20224,10 +20224,10 @@ __DEV__ &&
2022420224
(function () {
2022520225
var internals = {
2022620226
bundleType: 1,
20227-
version: "19.2.0-www-classic-df38ac9a-20250926",
20227+
version: "19.2.0-www-classic-047715c4-20250925",
2022820228
rendererPackageName: "react-art",
2022920229
currentDispatcherRef: ReactSharedInternals,
20230-
reconcilerVersion: "19.2.0-www-classic-df38ac9a-20250926"
20230+
reconcilerVersion: "19.2.0-www-classic-047715c4-20250925"
2023120231
};
2023220232
internals.overrideHookState = overrideHookState;
2023320233
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -20261,7 +20261,7 @@ __DEV__ &&
2026120261
exports.Shape = Shape;
2026220262
exports.Surface = Surface;
2026320263
exports.Text = Text;
20264-
exports.version = "19.2.0-www-classic-df38ac9a-20250926";
20264+
exports.version = "19.2.0-www-classic-047715c4-20250925";
2026520265
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
2026620266
"function" ===
2026720267
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.modern.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19995,10 +19995,10 @@ __DEV__ &&
1999519995
(function () {
1999619996
var internals = {
1999719997
bundleType: 1,
19998-
version: "19.2.0-www-modern-df38ac9a-20250926",
19998+
version: "19.2.0-www-modern-047715c4-20250925",
1999919999
rendererPackageName: "react-art",
2000020000
currentDispatcherRef: ReactSharedInternals,
20001-
reconcilerVersion: "19.2.0-www-modern-df38ac9a-20250926"
20001+
reconcilerVersion: "19.2.0-www-modern-047715c4-20250925"
2000220002
};
2000320003
internals.overrideHookState = overrideHookState;
2000420004
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -20032,7 +20032,7 @@ __DEV__ &&
2003220032
exports.Shape = Shape;
2003320033
exports.Surface = Surface;
2003420034
exports.Text = Text;
20035-
exports.version = "19.2.0-www-modern-df38ac9a-20250926";
20035+
exports.version = "19.2.0-www-modern-047715c4-20250925";
2003620036
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
2003720037
"function" ===
2003820038
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)