Resolve the .default export of a React.lazy as the canonical value (#34906)

For debug purposes this is the value that the `React.lazy` resolves to.
It also lets us look at that value for descriptions like its name.
This commit is contained in:
Sebastian Markbåge 2025-10-19 11:56:25 -07:00 committed by GitHub
parent 40c7a7f6ca
commit ec7d9a7249
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -20,6 +20,8 @@ import {enableAsyncDebugInfo} from 'shared/ReactFeatureFlags';
import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';
import noop from 'shared/noop';
const Uninitialized = -1;
const Pending = 0;
const Resolved = 1;
@ -67,12 +69,20 @@ export type LazyComponent<T, P> = {
function lazyInitializer<T>(payload: Payload<T>): T {
if (payload._status === Uninitialized) {
let resolveDebugValue: (void | T) => void = (null: any);
let rejectDebugValue: mixed => void = (null: any);
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Mark when we first kicked off the lazy request.
// $FlowFixMe[cannot-write]
ioInfo.start = ioInfo.end = performance.now();
// Stash a Promise for introspection of the value later.
// $FlowFixMe[cannot-write]
ioInfo.value = new Promise((resolve, reject) => {
resolveDebugValue = resolve;
rejectDebugValue = reject;
});
}
}
const ctor = payload._result;
@ -92,12 +102,20 @@ function lazyInitializer<T>(payload: Payload<T>): T {
const resolved: ResolvedPayload<T> = (payload: any);
resolved._status = Resolved;
resolved._result = moduleObject;
if (__DEV__) {
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Mark the end time of when we resolved.
// $FlowFixMe[cannot-write]
ioInfo.end = performance.now();
// Surface the default export as the resolved "value" for debug purposes.
const debugValue =
moduleObject == null ? undefined : moduleObject.default;
resolveDebugValue(debugValue);
// $FlowFixMe
ioInfo.value.status = 'fulfilled';
// $FlowFixMe
ioInfo.value.value = debugValue;
}
// Make the thenable introspectable
if (thenable.status === undefined) {
@ -124,6 +142,14 @@ function lazyInitializer<T>(payload: Payload<T>): T {
// Mark the end time of when we rejected.
// $FlowFixMe[cannot-write]
ioInfo.end = performance.now();
// Hide unhandled rejections.
// $FlowFixMe
ioInfo.value.then(noop, noop);
rejectDebugValue(error);
// $FlowFixMe
ioInfo.value.status = 'rejected';
// $FlowFixMe
ioInfo.value.reason = error;
}
// Make the thenable introspectable
if (thenable.status === undefined) {
@ -139,9 +165,6 @@ function lazyInitializer<T>(payload: Payload<T>): T {
if (__DEV__ && enableAsyncDebugInfo) {
const ioInfo = payload._ioInfo;
if (ioInfo != null) {
// Stash the thenable for introspection of the value later.
// $FlowFixMe[cannot-write]
ioInfo.value = thenable;
const displayName = thenable.displayName;
if (typeof displayName === 'string') {
// $FlowFixMe[cannot-write]