Repository: facebook/react
Pull request: Resolve the .default export of a React.lazy as the canonical value

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.

Changed files:
filename: packages/react/src/ReactLazy.js
patch: @@ -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]