Skip to content

Commit 390ac45

Browse files
committed
[Float][Fiber] Implement waitForCommitToBeReady for stylesheet resources (#26450)
Before a commit is finished if any new stylesheet resources are going to mount and we are capable of delaying the commit we will do the following 1. Wait for all preloads for newly created stylesheet resources to load 2. Once all preloads are finished we insert the stylesheet instances for these resources and wait for them all to load 3. Once all stylesheets have loaded we complete the commit In this PR I also removed the synchronous loadingstate tracking in the fizz runtime. It was not necessary to support the implementation on not used by the fizz runtime itself. It makes the inline script slightly smaller In this PR I also integrated ReactDOMFloatClient with ReactDOMHostConfig. It leads to better code factoring, something I already did on the server a while back. To make the diff a little easier to follow i make these changes in a single commit so you can look at the change after that commit if helpful There is a 500ms timeout which will finish the commit even if all suspended host instances have not finished loading yet At the moment error and load events are treated the same and we're really tracking whether the host instance is finished attempting to load. DiffTrain build for [73b6435](73b6435)
1 parent 1c9327e commit 390ac45

25 files changed

+73225
-69555
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
909c6dacfde06b87fa22f2e8506c47124cf982b5
1+
73b6435ca4e0c3ae3aac8126509a82420a84f0d7

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
}
2828
"use strict";
2929

30-
var ReactVersion = "18.3.0-www-modern-e3dcc95d";
30+
var ReactVersion = "18.3.0-www-modern-11df97fe";
3131

3232
// ATTENTION
3333
// When adding new symbols to this file,

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

Lines changed: 117 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-classic-7d98bb40";
72+
var ReactVersion = "18.3.0-www-classic-dfeb256e";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -2521,33 +2521,44 @@ function lanesToEventPriority(lanes) {
25212521

25222522
// Renderers that don't support hydration
25232523
// can re-export everything from this module.
2524-
function shim$1() {
2524+
function shim$2() {
25252525
throw new Error(
25262526
"The current renderer does not support hydration. " +
25272527
"This error is likely caused by a bug in React. " +
25282528
"Please file an issue."
25292529
);
25302530
} // Hydration (when unsupported)
2531-
var isSuspenseInstancePending = shim$1;
2532-
var isSuspenseInstanceFallback = shim$1;
2533-
var getSuspenseInstanceFallbackErrorDetails = shim$1;
2534-
var registerSuspenseInstanceRetry = shim$1;
2535-
var clearSuspenseBoundary = shim$1;
2536-
var clearSuspenseBoundaryFromContainer = shim$1;
2537-
var errorHydratingContainer = shim$1;
2531+
var isSuspenseInstancePending = shim$2;
2532+
var isSuspenseInstanceFallback = shim$2;
2533+
var getSuspenseInstanceFallbackErrorDetails = shim$2;
2534+
var registerSuspenseInstanceRetry = shim$2;
2535+
var clearSuspenseBoundary = shim$2;
2536+
var clearSuspenseBoundaryFromContainer = shim$2;
2537+
var errorHydratingContainer = shim$2;
25382538

25392539
// Renderers that don't support React Scopes
25402540
// can re-export everything from this module.
2541-
function shim() {
2541+
function shim$1() {
25422542
throw new Error(
25432543
"The current renderer does not support React Scopes. " +
25442544
"This error is likely caused by a bug in React. " +
25452545
"Please file an issue."
25462546
);
25472547
} // React Scopes (when unsupported)
25482548

2549-
var prepareScopeUpdate = shim;
2550-
var getInstanceFromScope = shim;
2549+
var prepareScopeUpdate = shim$1;
2550+
var getInstanceFromScope = shim$1;
2551+
2552+
// Renderers that don't support hydration
2553+
// can re-export everything from this module.
2554+
function shim() {
2555+
throw new Error(
2556+
"The current renderer does not support Resources. " +
2557+
"This error is likely caused by a bug in React. " +
2558+
"Please file an issue."
2559+
);
2560+
} // Resources (when unsupported)
2561+
var suspendResource = shim;
25512562

25522563
var pooledTransform = new Transform();
25532564
var NO_CONTEXT = {};
@@ -2923,6 +2934,9 @@ function unhideTextInstance(textInstance, text) {
29232934
function getInstanceFromNode(node) {
29242935
throw new Error("Not implemented.");
29252936
}
2937+
function maySuspendCommit(type, props) {
2938+
return false;
2939+
}
29262940
function preloadInstance(type, props) {
29272941
// Return true to indicate it's already loaded
29282942
return true;
@@ -5576,6 +5590,13 @@ function trackUsedThenable(thenableState, thenable, index) {
55765590
}
55775591
}
55785592
}
5593+
function suspendCommit() {
5594+
// This extra indirection only exists so it can handle passing
5595+
// noopSuspenseyCommitThenable through to throwException.
5596+
// TODO: Factor the thenable check out of throwException
5597+
suspendedThenable = noopSuspenseyCommitThenable;
5598+
throw SuspenseyCommitException;
5599+
} // This is used to track the actual thenable that suspended so it can be
55795600
// passed to the rest of the Suspense implementation — which, for historical
55805601
// reasons, expects to receive a thenable.
55815602

@@ -17687,16 +17708,28 @@ function preloadInstanceAndSuspendIfNeeded(
1768717708
props,
1768817709
renderLanes
1768917710
) {
17690-
// Ask the renderer if this instance should suspend the commit.
17691-
{
17692-
// If this flag was set previously, we can remove it. The flag represents
17693-
// whether this particular set of props might ever need to suspend. The
17694-
// safest thing to do is for maySuspendCommit to always return true, but
17695-
// if the renderer is reasonably confident that the underlying resource
17696-
// won't be evicted, it can return false as a performance optimization.
17697-
workInProgress.flags &= ~SuspenseyCommit;
17698-
return;
17699-
} // Mark this fiber with a flag. We use this right before the commit phase to
17711+
workInProgress.flags |= SuspenseyCommit; // Check if we're rendering at a "non-urgent" priority. This is the same
17712+
// check that `useDeferredValue` does to determine whether it needs to
17713+
// defer. This is partly for gradual adoption purposes (i.e. shouldn't start
17714+
// suspending until you opt in with startTransition or Suspense) but it
17715+
// also happens to be the desired behavior for the concrete use cases we've
17716+
// thought of so far, like CSS loading, fonts, images, etc.
17717+
// TODO: We may decide to expose a way to force a fallback even during a
17718+
// sync update.
17719+
17720+
if (!includesOnlyNonUrgentLanes(renderLanes));
17721+
else {
17722+
// Preload the instance
17723+
var isReady = preloadInstance();
17724+
17725+
if (!isReady) {
17726+
if (shouldRemainOnPreviousScreen());
17727+
else {
17728+
// Trigger a fallback rather than block the render.
17729+
suspendCommit();
17730+
}
17731+
}
17732+
}
1770017733
}
1770117734

1770217735
function scheduleRetryEffect(workInProgress, retryQueue) {
@@ -18129,6 +18162,8 @@ function completeWork(current, workInProgress, renderLanes) {
1812918162
popHostContext(workInProgress);
1813018163
var _type = workInProgress.type;
1813118164

18165+
var _maySuspend = maySuspendCommit();
18166+
1813218167
if (current !== null && workInProgress.stateNode != null) {
1813318168
updateHostComponent(current, workInProgress, _type, newProps);
1813418169

@@ -18183,7 +18218,17 @@ function completeWork(current, workInProgress, renderLanes) {
1818318218
// will resume rendering as if the work-in-progress completed. So it must
1818418219
// fully complete.
1818518220

18186-
preloadInstanceAndSuspendIfNeeded(workInProgress);
18221+
if (_maySuspend) {
18222+
preloadInstanceAndSuspendIfNeeded(
18223+
workInProgress,
18224+
_type,
18225+
newProps,
18226+
renderLanes
18227+
);
18228+
} else {
18229+
workInProgress.flags &= ~SuspenseyCommit;
18230+
}
18231+
1818718232
return null;
1818818233
}
1818918234

@@ -22559,6 +22604,50 @@ function commitPassiveUnmountEffects(finishedWork) {
2255922604
commitPassiveUnmountOnFiber(finishedWork);
2256022605
resetCurrentFiber();
2256122606
}
22607+
function accumulateSuspenseyCommit(finishedWork) {
22608+
accumulateSuspenseyCommitOnFiber(finishedWork);
22609+
}
22610+
22611+
function recursivelyAccumulateSuspenseyCommit(parentFiber) {
22612+
if (parentFiber.subtreeFlags & SuspenseyCommit) {
22613+
var child = parentFiber.child;
22614+
22615+
while (child !== null) {
22616+
accumulateSuspenseyCommitOnFiber(child);
22617+
child = child.sibling;
22618+
}
22619+
}
22620+
}
22621+
22622+
function accumulateSuspenseyCommitOnFiber(fiber) {
22623+
switch (fiber.tag) {
22624+
case HostHoistable: {
22625+
recursivelyAccumulateSuspenseyCommit(fiber);
22626+
22627+
if (fiber.flags & SuspenseyCommit) {
22628+
if (fiber.memoizedState !== null) {
22629+
suspendResource();
22630+
}
22631+
}
22632+
22633+
break;
22634+
}
22635+
22636+
case HostComponent: {
22637+
recursivelyAccumulateSuspenseyCommit(fiber);
22638+
22639+
break;
22640+
}
22641+
22642+
case HostRoot:
22643+
case HostPortal:
22644+
// eslint-disable-next-line-no-fallthrough
22645+
22646+
default: {
22647+
recursivelyAccumulateSuspenseyCommit(fiber);
22648+
}
22649+
}
22650+
}
2256222651

2256322652
function detachAlternateSiblings(parentFiber) {
2256422653
// A fiber was deleted from this parent fiber, but it's still part of the
@@ -24161,6 +24250,11 @@ function commitRootWhenReady(
2416124250
lanes
2416224251
) {
2416324252
if (includesOnlyNonUrgentLanes(lanes)) {
24253+
// the suspensey resources. The renderer is responsible for accumulating
24254+
// all the load events. This all happens in a single synchronous
24255+
// transaction, so it track state in its own module scope.
24256+
24257+
accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should
2416424258
// suspend. If it's not ready, it will return a callback to subscribe to
2416524259
// a ready event.
2416624260

0 commit comments

Comments
 (0)