Skip to content

Commit 879551c

Browse files
committed
Client render dehydrated Suspense boundaries on document load (facebook#31620)
When streaming SSR while hydrating React will wait for Suspense boundaries to be revealed by the SSR stream before attempting to hydrate them. The rationale here is that the Server render is likely further ahead of whatever the client would produce so waiting to let the server stream in the UI is preferable to retrying on the client and possibly delaying how quickly the primary content becomes available. However If the connection closes early (user hits stop for instance) or there is a server error which prevents additional HTML from being delivered to the client this can put React into a broken state where the boundary never resolves nor errors and the hydration never retries that boundary freezing it in it's fallback state. Once the document has fully loaded we know there is not way any additional Suspense boundaries can arrive. This update changes react-dom on the client to schedule client renders for any unfinished Suspense boundaries upon document loading. The technique for client rendering a fallback is pretty straight forward. When hydrating a Suspense boundary if the Document is in 'complete' readyState we interpret pending boundaries as fallback boundaries. If the readyState is not 'complete' we register an event to retry the boundary when the DOMContentLoaded event fires. To test this I needed JSDOM to model readyState. We previously had a temporary implementation of readyState for SSR streaming but I ended up implementing this as a mock of JSDOM that implements a fake readyState that is mutable. It starts off in 'loading' readyState and you can advance it by mutating document.readyState. You can also reset it to 'loading'. It fires events when changing states. This seems like the least invasive way to get closer-to-real-browser behavior in a way that won't require remembering this subtle detail every time you create a test that asserts Suspense resolution order. DiffTrain build for [16d2bbb](facebook@16d2bbb)
1 parent 9ece68a commit 879551c

34 files changed

+1160
-960
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2a9f4c04e54294b668e0a2ae11c1930c2e57b248
1+
16d2bbbd1f1617d636ea0fd271b902a12a763c27
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2a9f4c04e54294b668e0a2ae11c1930c2e57b248
1+
16d2bbbd1f1617d636ea0fd271b902a12a763c27

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1841,7 +1841,7 @@ __DEV__ &&
18411841
exports.useTransition = function () {
18421842
return resolveDispatcher().useTransition();
18431843
};
1844-
exports.version = "19.0.0-www-classic-2a9f4c04-20241122";
1844+
exports.version = "19.0.0-www-classic-16d2bbbd-20241203";
18451845
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
18461846
"function" ===
18471847
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1841,7 +1841,7 @@ __DEV__ &&
18411841
exports.useTransition = function () {
18421842
return resolveDispatcher().useTransition();
18431843
};
1844-
exports.version = "19.0.0-www-modern-2a9f4c04-20241122";
1844+
exports.version = "19.0.0-www-modern-16d2bbbd-20241203";
18451845
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
18461846
"function" ===
18471847
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,4 +634,4 @@ exports.useSyncExternalStore = function (
634634
exports.useTransition = function () {
635635
return ReactSharedInternals.H.useTransition();
636636
};
637-
exports.version = "19.0.0-www-classic-2a9f4c04-20241122";
637+
exports.version = "19.0.0-www-classic-16d2bbbd-20241203";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,4 +634,4 @@ exports.useSyncExternalStore = function (
634634
exports.useTransition = function () {
635635
return ReactSharedInternals.H.useTransition();
636636
};
637-
exports.version = "19.0.0-www-modern-2a9f4c04-20241122";
637+
exports.version = "19.0.0-www-modern-16d2bbbd-20241203";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ exports.useSyncExternalStore = function (
638638
exports.useTransition = function () {
639639
return ReactSharedInternals.H.useTransition();
640640
};
641-
exports.version = "19.0.0-www-classic-2a9f4c04-20241122";
641+
exports.version = "19.0.0-www-classic-16d2bbbd-20241203";
642642
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
643643
"function" ===
644644
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ exports.useSyncExternalStore = function (
638638
exports.useTransition = function () {
639639
return ReactSharedInternals.H.useTransition();
640640
};
641-
exports.version = "19.0.0-www-modern-2a9f4c04-20241122";
641+
exports.version = "19.0.0-www-modern-16d2bbbd-20241203";
642642
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
643643
"function" ===
644644
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
@@ -17125,11 +17125,11 @@ __DEV__ &&
1712517125
(function () {
1712617126
var internals = {
1712717127
bundleType: 1,
17128-
version: "19.0.0-www-classic-2a9f4c04-20241122",
17128+
version: "19.0.0-www-classic-16d2bbbd-20241203",
1712917129
rendererPackageName: "react-art",
1713017130
currentDispatcherRef: ReactSharedInternals,
1713117131
findFiberByHostInstance: getInstanceFromNode,
17132-
reconcilerVersion: "19.0.0-www-classic-2a9f4c04-20241122"
17132+
reconcilerVersion: "19.0.0-www-classic-16d2bbbd-20241203"
1713317133
};
1713417134
internals.overrideHookState = overrideHookState;
1713517135
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -17163,7 +17163,7 @@ __DEV__ &&
1716317163
exports.Shape = Shape;
1716417164
exports.Surface = Surface;
1716517165
exports.Text = Text;
17166-
exports.version = "19.0.0-www-classic-2a9f4c04-20241122";
17166+
exports.version = "19.0.0-www-classic-16d2bbbd-20241203";
1716717167
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1716817168
"function" ===
1716917169
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
@@ -16888,11 +16888,11 @@ __DEV__ &&
1688816888
(function () {
1688916889
var internals = {
1689016890
bundleType: 1,
16891-
version: "19.0.0-www-modern-2a9f4c04-20241122",
16891+
version: "19.0.0-www-modern-16d2bbbd-20241203",
1689216892
rendererPackageName: "react-art",
1689316893
currentDispatcherRef: ReactSharedInternals,
1689416894
findFiberByHostInstance: getInstanceFromNode,
16895-
reconcilerVersion: "19.0.0-www-modern-2a9f4c04-20241122"
16895+
reconcilerVersion: "19.0.0-www-modern-16d2bbbd-20241203"
1689616896
};
1689716897
internals.overrideHookState = overrideHookState;
1689816898
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16926,7 +16926,7 @@ __DEV__ &&
1692616926
exports.Shape = Shape;
1692716927
exports.Surface = Surface;
1692816928
exports.Text = Text;
16929-
exports.version = "19.0.0-www-modern-2a9f4c04-20241122";
16929+
exports.version = "19.0.0-www-modern-16d2bbbd-20241203";
1693016930
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1693116931
"function" ===
1693216932
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10824,13 +10824,13 @@ var slice = Array.prototype.slice,
1082410824
})(React.Component);
1082510825
var internals$jscomp$inline_1509 = {
1082610826
bundleType: 0,
10827-
version: "19.0.0-www-classic-2a9f4c04-20241122",
10827+
version: "19.0.0-www-classic-16d2bbbd-20241203",
1082810828
rendererPackageName: "react-art",
1082910829
currentDispatcherRef: ReactSharedInternals,
1083010830
findFiberByHostInstance: function () {
1083110831
return null;
1083210832
},
10833-
reconcilerVersion: "19.0.0-www-classic-2a9f4c04-20241122"
10833+
reconcilerVersion: "19.0.0-www-classic-16d2bbbd-20241203"
1083410834
};
1083510835
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1083610836
var hook$jscomp$inline_1510 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -10856,4 +10856,4 @@ exports.RadialGradient = RadialGradient;
1085610856
exports.Shape = TYPES.SHAPE;
1085710857
exports.Surface = Surface;
1085810858
exports.Text = Text;
10859-
exports.version = "19.0.0-www-classic-2a9f4c04-20241122";
10859+
exports.version = "19.0.0-www-classic-16d2bbbd-20241203";

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10540,13 +10540,13 @@ var slice = Array.prototype.slice,
1054010540
})(React.Component);
1054110541
var internals$jscomp$inline_1488 = {
1054210542
bundleType: 0,
10543-
version: "19.0.0-www-modern-2a9f4c04-20241122",
10543+
version: "19.0.0-www-modern-16d2bbbd-20241203",
1054410544
rendererPackageName: "react-art",
1054510545
currentDispatcherRef: ReactSharedInternals,
1054610546
findFiberByHostInstance: function () {
1054710547
return null;
1054810548
},
10549-
reconcilerVersion: "19.0.0-www-modern-2a9f4c04-20241122"
10549+
reconcilerVersion: "19.0.0-www-modern-16d2bbbd-20241203"
1055010550
};
1055110551
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1055210552
var hook$jscomp$inline_1489 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -10572,4 +10572,4 @@ exports.RadialGradient = RadialGradient;
1057210572
exports.Shape = TYPES.SHAPE;
1057310573
exports.Surface = Surface;
1057410574
exports.Text = Text;
10575-
exports.version = "19.0.0-www-modern-2a9f4c04-20241122";
10575+
exports.version = "19.0.0-www-modern-16d2bbbd-20241203";

0 commit comments

Comments
 (0)