Skip to content

Commit 6a86afb

Browse files
committed
[Fizz] Do not reinsert stylesheets after initial insert (#27586)
The loading state tracking for suspensey CSS is too complicated. Prior to this change it had a state it could enter into where a stylesheet was already in the DOM but the loading state did not know it was inserted causing a later transition to try to insert it again. This fix is to add proper tracking of insertions on the codepaths that were missing it. It also modifies the logic of when to suspend based on whether the stylesheet has already been inserted or not. This is not 100% correct semantics however because a prior commit could have inserted a stylesheet and a later transition should ideally be able to wait on that load before committing. I haven't attempted to fix this yet however because the loading state tracking is too complicated as it is and requires a more thorough refactor. Additionally it's not particularly valuable to delay a transition on a loading stylesheet when a previous commit also relied on that stylesheet but didn't wait for it b/c it was sync. I will follow up with an improvement PR later fixes: #27585 DiffTrain build for [a998552](a998552)
1 parent 76600e4 commit 6a86afb

14 files changed

+292
-262
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
51ffd3564f97b58737df395d30628a27fa71a39d
1+
a9985529f1aa55477f0feafe2398d36707cf6108

compiled/facebook-www/React-dev.classic.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-classic-273dc50b";
30+
var ReactVersion = "18.3.0-www-classic-8d8af9ad";
3131

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,4 +579,4 @@ exports.useSyncExternalStore = function (
579579
exports.useTransition = function () {
580580
return ReactCurrentDispatcher.current.useTransition();
581581
};
582-
exports.version = "18.3.0-www-modern-4e6d4d90";
582+
exports.version = "18.3.0-www-modern-ac0f5360";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ exports.useSyncExternalStore = function (
590590
exports.useTransition = function () {
591591
return ReactCurrentDispatcher.current.useTransition();
592592
};
593-
exports.version = "18.3.0-www-modern-035cd9a2";
593+
exports.version = "18.3.0-www-modern-a09b3b42";
594594

595595
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
596596
if (

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

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -34159,7 +34159,7 @@ function createFiberRoot(
3415934159
return root;
3416034160
}
3416134161

34162-
var ReactVersion = "18.3.0-www-classic-0db07969";
34162+
var ReactVersion = "18.3.0-www-classic-c09aff01";
3416334163

3416434164
function createPortal$1(
3416534165
children,
@@ -43312,7 +43312,7 @@ function preinitStyle(href, precedence, options) {
4331243312
);
4331343313

4331443314
if (instance) {
43315-
state.loading = Loaded;
43315+
state.loading = Loaded & Inserted;
4331643316
} else {
4331743317
// Construct a new instance and insert it
4331843318
var stylesheetProps = assign(
@@ -43721,6 +43721,7 @@ function acquireResource(hoistableRoot, resource, props) {
4372143721
);
4372243722

4372343723
if (_instance) {
43724+
resource.state.loading |= Inserted;
4372443725
resource.instance = _instance;
4372543726
markNodeAsHoistable(_instance);
4372643727
return _instance;
@@ -44306,74 +44307,76 @@ function suspendResource(hoistableRoot, resource, props) {
4430644307
}
4430744308
}
4430844309

44309-
if (resource.instance === null) {
44310-
var qualifiedProps = props;
44311-
var key = getStyleKey(qualifiedProps.href); // Attempt to hydrate instance from DOM
44310+
if ((resource.state.loading & Inserted) === NotLoaded) {
44311+
if (resource.instance === null) {
44312+
var qualifiedProps = props;
44313+
var key = getStyleKey(qualifiedProps.href); // Attempt to hydrate instance from DOM
4431244314

44313-
var instance = hoistableRoot.querySelector(
44314-
getStylesheetSelectorFromKey(key)
44315-
);
44315+
var instance = hoistableRoot.querySelector(
44316+
getStylesheetSelectorFromKey(key)
44317+
);
4431644318

44317-
if (instance) {
44318-
// If this instance has a loading state it came from the Fizz runtime.
44319-
// If there is not loading state it is assumed to have been server rendered
44320-
// as part of the preamble and therefore synchronously loaded. It could have
44321-
// errored however which we still do not yet have a means to detect. For now
44322-
// we assume it is loaded.
44323-
var maybeLoadingState = instance._p;
44319+
if (instance) {
44320+
// If this instance has a loading state it came from the Fizz runtime.
44321+
// If there is not loading state it is assumed to have been server rendered
44322+
// as part of the preamble and therefore synchronously loaded. It could have
44323+
// errored however which we still do not yet have a means to detect. For now
44324+
// we assume it is loaded.
44325+
var maybeLoadingState = instance._p;
4432444326

44325-
if (
44326-
maybeLoadingState !== null &&
44327-
typeof maybeLoadingState === "object" && // $FlowFixMe[method-unbinding]
44328-
typeof maybeLoadingState.then === "function"
44329-
) {
44330-
var loadingState = maybeLoadingState;
44331-
state.count++;
44332-
var ping = onUnsuspend.bind(state);
44333-
loadingState.then(ping, ping);
44334-
}
44327+
if (
44328+
maybeLoadingState !== null &&
44329+
typeof maybeLoadingState === "object" && // $FlowFixMe[method-unbinding]
44330+
typeof maybeLoadingState.then === "function"
44331+
) {
44332+
var loadingState = maybeLoadingState;
44333+
state.count++;
44334+
var ping = onUnsuspend.bind(state);
44335+
loadingState.then(ping, ping);
44336+
}
4433544337

44336-
resource.state.loading |= Inserted;
44337-
resource.instance = instance;
44338-
markNodeAsHoistable(instance);
44339-
return;
44340-
}
44338+
resource.state.loading |= Inserted;
44339+
resource.instance = instance;
44340+
markNodeAsHoistable(instance);
44341+
return;
44342+
}
4434144343

44342-
var ownerDocument = getDocumentFromRoot(hoistableRoot);
44343-
var stylesheetProps = stylesheetPropsFromRawProps(props);
44344-
var preloadProps = preloadPropsMap.get(key);
44344+
var ownerDocument = getDocumentFromRoot(hoistableRoot);
44345+
var stylesheetProps = stylesheetPropsFromRawProps(props);
44346+
var preloadProps = preloadPropsMap.get(key);
4434544347

44346-
if (preloadProps) {
44347-
adoptPreloadPropsForStylesheet(stylesheetProps, preloadProps);
44348-
} // Construct and insert a new instance
44348+
if (preloadProps) {
44349+
adoptPreloadPropsForStylesheet(stylesheetProps, preloadProps);
44350+
} // Construct and insert a new instance
4434944351

44350-
instance = ownerDocument.createElement("link");
44351-
markNodeAsHoistable(instance);
44352-
var linkInstance = instance; // This Promise is a loading state used by the Fizz runtime. We need this incase there is a race
44353-
// between this resource being rendered on the client and being rendered with a late completed boundary.
44352+
instance = ownerDocument.createElement("link");
44353+
markNodeAsHoistable(instance);
44354+
var linkInstance = instance; // This Promise is a loading state used by the Fizz runtime. We need this incase there is a race
44355+
// between this resource being rendered on the client and being rendered with a late completed boundary.
4435444356

44355-
linkInstance._p = new Promise(function (resolve, reject) {
44356-
linkInstance.onload = resolve;
44357-
linkInstance.onerror = reject;
44358-
});
44359-
setInitialProperties(instance, "link", stylesheetProps);
44360-
resource.instance = instance;
44361-
}
44357+
linkInstance._p = new Promise(function (resolve, reject) {
44358+
linkInstance.onload = resolve;
44359+
linkInstance.onerror = reject;
44360+
});
44361+
setInitialProperties(instance, "link", stylesheetProps);
44362+
resource.instance = instance;
44363+
}
4436244364

44363-
if (state.stylesheets === null) {
44364-
state.stylesheets = new Map();
44365-
}
44365+
if (state.stylesheets === null) {
44366+
state.stylesheets = new Map();
44367+
}
4436644368

44367-
state.stylesheets.set(resource, hoistableRoot);
44368-
var preloadEl = resource.state.preload;
44369+
state.stylesheets.set(resource, hoistableRoot);
44370+
var preloadEl = resource.state.preload;
4436944371

44370-
if (preloadEl && (resource.state.loading & Settled) === NotLoaded) {
44371-
state.count++;
44372+
if (preloadEl && (resource.state.loading & Settled) === NotLoaded) {
44373+
state.count++;
4437244374

44373-
var _ping = onUnsuspend.bind(state);
44375+
var _ping = onUnsuspend.bind(state);
4437444376

44375-
preloadEl.addEventListener("load", _ping);
44376-
preloadEl.addEventListener("error", _ping);
44377+
preloadEl.addEventListener("load", _ping);
44378+
preloadEl.addEventListener("error", _ping);
44379+
}
4437744380
}
4437844381
}
4437944382
}

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

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -34004,7 +34004,7 @@ function createFiberRoot(
3400434004
return root;
3400534005
}
3400634006

34007-
var ReactVersion = "18.3.0-www-modern-b2fbd9ab";
34007+
var ReactVersion = "18.3.0-www-modern-32f0b929";
3400834008

3400934009
function createPortal$1(
3401034010
children,
@@ -43822,7 +43822,7 @@ function preinitStyle(href, precedence, options) {
4382243822
);
4382343823

4382443824
if (instance) {
43825-
state.loading = Loaded;
43825+
state.loading = Loaded & Inserted;
4382643826
} else {
4382743827
// Construct a new instance and insert it
4382843828
var stylesheetProps = assign(
@@ -44231,6 +44231,7 @@ function acquireResource(hoistableRoot, resource, props) {
4423144231
);
4423244232

4423344233
if (_instance) {
44234+
resource.state.loading |= Inserted;
4423444235
resource.instance = _instance;
4423544236
markNodeAsHoistable(_instance);
4423644237
return _instance;
@@ -44816,74 +44817,76 @@ function suspendResource(hoistableRoot, resource, props) {
4481644817
}
4481744818
}
4481844819

44819-
if (resource.instance === null) {
44820-
var qualifiedProps = props;
44821-
var key = getStyleKey(qualifiedProps.href); // Attempt to hydrate instance from DOM
44820+
if ((resource.state.loading & Inserted) === NotLoaded) {
44821+
if (resource.instance === null) {
44822+
var qualifiedProps = props;
44823+
var key = getStyleKey(qualifiedProps.href); // Attempt to hydrate instance from DOM
4482244824

44823-
var instance = hoistableRoot.querySelector(
44824-
getStylesheetSelectorFromKey(key)
44825-
);
44825+
var instance = hoistableRoot.querySelector(
44826+
getStylesheetSelectorFromKey(key)
44827+
);
4482644828

44827-
if (instance) {
44828-
// If this instance has a loading state it came from the Fizz runtime.
44829-
// If there is not loading state it is assumed to have been server rendered
44830-
// as part of the preamble and therefore synchronously loaded. It could have
44831-
// errored however which we still do not yet have a means to detect. For now
44832-
// we assume it is loaded.
44833-
var maybeLoadingState = instance._p;
44829+
if (instance) {
44830+
// If this instance has a loading state it came from the Fizz runtime.
44831+
// If there is not loading state it is assumed to have been server rendered
44832+
// as part of the preamble and therefore synchronously loaded. It could have
44833+
// errored however which we still do not yet have a means to detect. For now
44834+
// we assume it is loaded.
44835+
var maybeLoadingState = instance._p;
4483444836

44835-
if (
44836-
maybeLoadingState !== null &&
44837-
typeof maybeLoadingState === "object" && // $FlowFixMe[method-unbinding]
44838-
typeof maybeLoadingState.then === "function"
44839-
) {
44840-
var loadingState = maybeLoadingState;
44841-
state.count++;
44842-
var ping = onUnsuspend.bind(state);
44843-
loadingState.then(ping, ping);
44844-
}
44837+
if (
44838+
maybeLoadingState !== null &&
44839+
typeof maybeLoadingState === "object" && // $FlowFixMe[method-unbinding]
44840+
typeof maybeLoadingState.then === "function"
44841+
) {
44842+
var loadingState = maybeLoadingState;
44843+
state.count++;
44844+
var ping = onUnsuspend.bind(state);
44845+
loadingState.then(ping, ping);
44846+
}
4484544847

44846-
resource.state.loading |= Inserted;
44847-
resource.instance = instance;
44848-
markNodeAsHoistable(instance);
44849-
return;
44850-
}
44848+
resource.state.loading |= Inserted;
44849+
resource.instance = instance;
44850+
markNodeAsHoistable(instance);
44851+
return;
44852+
}
4485144853

44852-
var ownerDocument = getDocumentFromRoot(hoistableRoot);
44853-
var stylesheetProps = stylesheetPropsFromRawProps(props);
44854-
var preloadProps = preloadPropsMap.get(key);
44854+
var ownerDocument = getDocumentFromRoot(hoistableRoot);
44855+
var stylesheetProps = stylesheetPropsFromRawProps(props);
44856+
var preloadProps = preloadPropsMap.get(key);
4485544857

44856-
if (preloadProps) {
44857-
adoptPreloadPropsForStylesheet(stylesheetProps, preloadProps);
44858-
} // Construct and insert a new instance
44858+
if (preloadProps) {
44859+
adoptPreloadPropsForStylesheet(stylesheetProps, preloadProps);
44860+
} // Construct and insert a new instance
4485944861

44860-
instance = ownerDocument.createElement("link");
44861-
markNodeAsHoistable(instance);
44862-
var linkInstance = instance; // This Promise is a loading state used by the Fizz runtime. We need this incase there is a race
44863-
// between this resource being rendered on the client and being rendered with a late completed boundary.
44862+
instance = ownerDocument.createElement("link");
44863+
markNodeAsHoistable(instance);
44864+
var linkInstance = instance; // This Promise is a loading state used by the Fizz runtime. We need this incase there is a race
44865+
// between this resource being rendered on the client and being rendered with a late completed boundary.
4486444866

44865-
linkInstance._p = new Promise(function (resolve, reject) {
44866-
linkInstance.onload = resolve;
44867-
linkInstance.onerror = reject;
44868-
});
44869-
setInitialProperties(instance, "link", stylesheetProps);
44870-
resource.instance = instance;
44871-
}
44867+
linkInstance._p = new Promise(function (resolve, reject) {
44868+
linkInstance.onload = resolve;
44869+
linkInstance.onerror = reject;
44870+
});
44871+
setInitialProperties(instance, "link", stylesheetProps);
44872+
resource.instance = instance;
44873+
}
4487244874

44873-
if (state.stylesheets === null) {
44874-
state.stylesheets = new Map();
44875-
}
44875+
if (state.stylesheets === null) {
44876+
state.stylesheets = new Map();
44877+
}
4487644878

44877-
state.stylesheets.set(resource, hoistableRoot);
44878-
var preloadEl = resource.state.preload;
44879+
state.stylesheets.set(resource, hoistableRoot);
44880+
var preloadEl = resource.state.preload;
4487944881

44880-
if (preloadEl && (resource.state.loading & Settled) === NotLoaded) {
44881-
state.count++;
44882+
if (preloadEl && (resource.state.loading & Settled) === NotLoaded) {
44883+
state.count++;
4488244884

44883-
var _ping = onUnsuspend.bind(state);
44885+
var _ping = onUnsuspend.bind(state);
4488444886

44885-
preloadEl.addEventListener("load", _ping);
44886-
preloadEl.addEventListener("error", _ping);
44887+
preloadEl.addEventListener("load", _ping);
44888+
preloadEl.addEventListener("error", _ping);
44889+
}
4488744890
}
4488844891
}
4488944892
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15149,7 +15149,7 @@ function preinitStyle(href, precedence, options) {
1514915149
getStylesheetSelectorFromKey(key)
1515015150
))
1515115151
)
15152-
state.loading = 1;
15152+
state.loading = 0;
1515315153
else {
1515415154
href = assign(
1515515155
{ rel: "stylesheet", href: href, "data-precedence": precedence },
@@ -15375,6 +15375,7 @@ function acquireResource(hoistableRoot, resource, props) {
1537515375
);
1537615376
if (instance$259)
1537715377
return (
15378+
(resource.state.loading |= 4),
1537815379
(resource.instance = instance$259),
1537915380
markNodeAsHoistable(instance$259),
1538015381
instance$259
@@ -15554,7 +15555,9 @@ function suspendResource(hoistableRoot, resource, props) {
1555415555
var state = suspendedState;
1555515556
if (
1555615557
"stylesheet" === resource.type &&
15557-
("string" !== typeof props.media || !1 !== matchMedia(props.media).matches)
15558+
("string" !== typeof props.media ||
15559+
!1 !== matchMedia(props.media).matches) &&
15560+
0 === (resource.state.loading & 4)
1555815561
) {
1555915562
if (null === resource.instance) {
1556015563
var key = getStyleKey(props.href),
@@ -16482,7 +16485,7 @@ Internals.Events = [
1648216485
var devToolsConfig$jscomp$inline_1796 = {
1648316486
findFiberByHostInstance: getClosestInstanceFromNode,
1648416487
bundleType: 0,
16485-
version: "18.3.0-www-classic-217e3cb6",
16488+
version: "18.3.0-www-classic-372e3020",
1648616489
rendererPackageName: "react-dom"
1648716490
};
1648816491
var internals$jscomp$inline_2142 = {
@@ -16512,7 +16515,7 @@ var internals$jscomp$inline_2142 = {
1651216515
scheduleRoot: null,
1651316516
setRefreshHandler: null,
1651416517
getCurrentFiber: null,
16515-
reconcilerVersion: "18.3.0-www-classic-217e3cb6"
16518+
reconcilerVersion: "18.3.0-www-classic-372e3020"
1651616519
};
1651716520
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
1651816521
var hook$jscomp$inline_2143 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -16849,4 +16852,4 @@ exports.useFormState = function () {
1684916852
exports.useFormStatus = function () {
1685016853
throw Error(formatProdErrorMessage(248));
1685116854
};
16852-
exports.version = "18.3.0-www-classic-217e3cb6";
16855+
exports.version = "18.3.0-www-classic-372e3020";

0 commit comments

Comments
 (0)