Skip to content

Commit 47d848a

Browse files
committed
[Fiber] InvokeGuardedCallback without metaprogramming (#26569)
InvokeGuardedCallback is now implemented with the browser fork done at error-time rather than module-load-time. Originally it also tried to freeze the window/document references to avoid mismatches in prototype chains when testing React in different documents however we have since updated our tests to not do this and it was a test only feature so I removed it. DiffTrain build for commit cc93a85.
1 parent ce24091 commit 47d848a

File tree

13 files changed

+175
-238
lines changed

13 files changed

+175
-238
lines changed

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js

Lines changed: 53 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<43355784ad4a055ab0a02e5c5e648c88>>
10+
* @generated SignedSource<<a8437bee4ca7ca2a6e95eed698390cea>>
1111
*/
1212

1313
'use strict';
@@ -16152,71 +16152,40 @@ function unwindInterruptedWork(current, interruptedWork, renderLanes) {
1615216152
}
1615316153
}
1615416154

16155-
// $FlowFixMe[missing-this-annot]
16156-
function invokeGuardedCallbackProd(name, func, context) {
16157-
// $FlowFixMe[method-unbinding]
16158-
var funcArgs = Array.prototype.slice.call(arguments, 3);
16159-
16160-
try {
16161-
// $FlowFixMe[incompatible-call] Flow doesn't understand the arguments splicing.
16162-
func.apply(context, funcArgs);
16163-
} catch (error) {
16164-
this.onError(error);
16165-
}
16166-
}
16167-
16168-
var invokeGuardedCallbackImpl = invokeGuardedCallbackProd;
16155+
var fakeNode = null;
1616916156

1617016157
{
16171-
// In DEV mode, we swap out invokeGuardedCallback for a special version
16172-
// that plays more nicely with the browser's DevTools. The idea is to preserve
16173-
// "Pause on exceptions" behavior. Because React wraps all user-provided
16174-
// functions in invokeGuardedCallback, and the production version of
16175-
// invokeGuardedCallback uses a try-catch, all user exceptions are treated
16176-
// like caught exceptions, and the DevTools won't pause unless the developer
16177-
// takes the extra step of enabling pause on caught exceptions. This is
16178-
// unintuitive, though, because even though React has caught the error, from
16179-
// the developer's perspective, the error is uncaught.
16180-
//
16181-
// To preserve the expected "Pause on exceptions" behavior, we don't use a
16182-
// try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake
16183-
// DOM node, and call the user-provided callback from inside an event handler
16184-
// for that fake event. If the callback throws, the error is "captured" using
16185-
// a global event handler. But because the error happens in a different
16186-
// event loop context, it does not interrupt the normal program flow.
16187-
// Effectively, this gives us try-catch behavior without actually using
16188-
// try-catch. Neat!
16189-
// Check that the browser supports the APIs we need to implement our special
16190-
// DEV version of invokeGuardedCallback
1619116158
if (
1619216159
typeof window !== "undefined" &&
1619316160
typeof window.dispatchEvent === "function" &&
1619416161
typeof document !== "undefined" && // $FlowFixMe[method-unbinding]
1619516162
typeof document.createEvent === "function"
1619616163
) {
16197-
var fakeNode = document.createElement("react");
16198-
16199-
invokeGuardedCallbackImpl = function invokeGuardedCallbackDev(
16200-
name,
16201-
func,
16202-
context
16203-
) {
16204-
// If document doesn't exist we know for sure we will crash in this method
16205-
// when we call document.createEvent(). However this can cause confusing
16206-
// errors: https://github.com/facebook/create-react-app/issues/3482
16207-
// So we preemptively throw with a better message instead.
16208-
if (typeof document === "undefined" || document === null) {
16209-
throw new Error(
16210-
"The `document` global was defined when React was initialized, but is not " +
16211-
"defined anymore. This can happen in a test environment if a component " +
16212-
"schedules an update from an asynchronous callback, but the test has already " +
16213-
"finished running. To solve this, you can either unmount the component at " +
16214-
"the end of your test (and ensure that any asynchronous operations get " +
16215-
"canceled in `componentWillUnmount`), or you can change the test itself " +
16216-
"to be asynchronous."
16217-
);
16218-
}
16164+
fakeNode = document.createElement("react");
16165+
}
16166+
}
1621916167

16168+
function invokeGuardedCallbackImpl(name, func, context) {
16169+
{
16170+
// In DEV mode, we use a special version
16171+
// that plays more nicely with the browser's DevTools. The idea is to preserve
16172+
// "Pause on exceptions" behavior. Because React wraps all user-provided
16173+
// functions in invokeGuardedCallback, and the production version of
16174+
// invokeGuardedCallback uses a try-catch, all user exceptions are treated
16175+
// like caught exceptions, and the DevTools won't pause unless the developer
16176+
// takes the extra step of enabling pause on caught exceptions. This is
16177+
// unintuitive, though, because even though React has caught the error, from
16178+
// the developer's perspective, the error is uncaught.
16179+
//
16180+
// To preserve the expected "Pause on exceptions" behavior, we don't use a
16181+
// try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake
16182+
// DOM node, and call the user-provided callback from inside an event handler
16183+
// for that fake event. If the callback throws, the error is "captured" using
16184+
// event loop context, it does not interrupt the normal program flow.
16185+
// Effectively, this gives us try-catch behavior without actually using
16186+
// try-catch. Neat!
16187+
// fakeNode signifies we are in an environment with a document and window object
16188+
if (fakeNode) {
1622016189
var evt = document.createEvent("Event");
1622116190
var didCall = false; // Keeps track of whether the user-provided callback threw an error. We
1622216191
// set this to true at the beginning, then set it to false right after
@@ -16237,7 +16206,7 @@ var invokeGuardedCallbackImpl = invokeGuardedCallbackProd;
1623716206
"event"
1623816207
);
1623916208

16240-
function restoreAfterDispatch() {
16209+
var restoreAfterDispatch = function () {
1624116210
// We immediately remove the callback from event listeners so that
1624216211
// nested `invokeGuardedCallback` calls do not clash. Otherwise, a
1624316212
// nested call would trigger the fake event handlers of any call higher
@@ -16253,20 +16222,20 @@ var invokeGuardedCallbackImpl = invokeGuardedCallbackProd;
1625316222
) {
1625416223
window.event = windowEvent;
1625516224
}
16256-
} // Create an event handler for our fake event. We will synchronously
16225+
}; // Create an event handler for our fake event. We will synchronously
1625716226
// dispatch our fake event using `dispatchEvent`. Inside the handler, we
1625816227
// call the user-provided callback.
1625916228
// $FlowFixMe[method-unbinding]
1626016229

16261-
var funcArgs = Array.prototype.slice.call(arguments, 3);
16230+
var _funcArgs = Array.prototype.slice.call(arguments, 3);
1626216231

16263-
function callCallback() {
16232+
var callCallback = function () {
1626416233
didCall = true;
1626516234
restoreAfterDispatch(); // $FlowFixMe[incompatible-call] Flow doesn't understand the arguments splicing.
1626616235

16267-
func.apply(context, funcArgs);
16236+
func.apply(context, _funcArgs);
1626816237
didError = false;
16269-
} // Create a global error event handler. We use this to capture the value
16238+
}; // Create a global error event handler. We use this to capture the value
1627016239
// that was thrown. It's possible that this error handler will fire more
1627116240
// than once; for example, if non-React code also calls `dispatchEvent`
1627216241
// and a handler for that event throws. We should be resilient to most of
@@ -16281,9 +16250,9 @@ var invokeGuardedCallbackImpl = invokeGuardedCallbackProd;
1628116250
var error; // Use this to track whether the error event is ever called.
1628216251

1628316252
var didSetError = false;
16284-
var isCrossOriginError = false; // $FlowFixMe[missing-local-annot]
16253+
var isCrossOriginError = false;
1628516254

16286-
function handleWindowError(event) {
16255+
var handleWindowError = function (event) {
1628716256
error = event.error;
1628816257
didSetError = true;
1628916258

@@ -16303,7 +16272,7 @@ var invokeGuardedCallbackImpl = invokeGuardedCallbackProd;
1630316272
}
1630416273
}
1630516274
}
16306-
} // Create a fake event type.
16275+
}; // Create a fake event type.
1630716276

1630816277
var evtType = "react-" + (name ? name : "invokeguardedcallback"); // Attach our event handlers
1630916278

@@ -16346,20 +16315,30 @@ var invokeGuardedCallbackImpl = invokeGuardedCallbackProd;
1634616315

1634716316
window.removeEventListener("error", handleWindowError);
1634816317

16349-
if (!didCall) {
16318+
if (didCall) {
16319+
return;
16320+
} else {
1635016321
// Something went really wrong, and our event was not dispatched.
1635116322
// https://github.com/facebook/react/issues/16734
1635216323
// https://github.com/facebook/react/issues/16585
1635316324
// Fall back to the production implementation.
16354-
restoreAfterDispatch();
16355-
return invokeGuardedCallbackProd.apply(this, arguments);
16325+
restoreAfterDispatch(); // we fall through and call the prod version instead
1635616326
}
16357-
};
16327+
} // We only get here if we are in an environment that either does not support the browser
16328+
// variant or we had trouble getting the browser to emit the error.
16329+
// $FlowFixMe[method-unbinding]
16330+
16331+
var funcArgs = Array.prototype.slice.call(arguments, 3);
16332+
16333+
try {
16334+
// $FlowFixMe[incompatible-call] Flow doesn't understand the arguments splicing.
16335+
func.apply(context, funcArgs);
16336+
} catch (error) {
16337+
this.onError(error);
16338+
}
1635816339
}
1635916340
}
1636016341

16361-
var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl;
16362-
1636316342
var hasError = false;
1636416343
var caughtError = null; // Used by event system to capture/rethrow the first error.
1636516344
var reporter = {
@@ -16385,7 +16364,7 @@ var reporter = {
1638516364
function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) {
1638616365
hasError = false;
1638716366
caughtError = null;
16388-
invokeGuardedCallbackImpl$1.apply(reporter, arguments);
16367+
invokeGuardedCallbackImpl.apply(reporter, arguments);
1638916368
}
1639016369
function clearCaughtError() {
1639116370
if (hasError) {
@@ -23859,7 +23838,7 @@ function createFiberRoot(
2385923838
return root;
2386023839
}
2386123840

23862-
var ReactVersion = "18.3.0-next-fdad813ac-20230420";
23841+
var ReactVersion = "18.3.0-next-cc93a8533-20230420";
2386323842

2386423843
// Might add PROFILE later.
2386523844

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-prod.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8599,7 +8599,7 @@ var devToolsConfig$jscomp$inline_1021 = {
85998599
throw Error("TestRenderer does not support findFiberByHostInstance()");
86008600
},
86018601
bundleType: 0,
8602-
version: "18.3.0-next-fdad813ac-20230420",
8602+
version: "18.3.0-next-cc93a8533-20230420",
86038603
rendererPackageName: "react-test-renderer"
86048604
};
86058605
var internals$jscomp$inline_1206 = {
@@ -8630,7 +8630,7 @@ var internals$jscomp$inline_1206 = {
86308630
scheduleRoot: null,
86318631
setRefreshHandler: null,
86328632
getCurrentFiber: null,
8633-
reconcilerVersion: "18.3.0-next-fdad813ac-20230420"
8633+
reconcilerVersion: "18.3.0-next-cc93a8533-20230420"
86348634
};
86358635
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
86368636
var hook$jscomp$inline_1207 = __REACT_DEVTOOLS_GLOBAL_HOOK__;

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-profiling.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9025,7 +9025,7 @@ var devToolsConfig$jscomp$inline_1063 = {
90259025
throw Error("TestRenderer does not support findFiberByHostInstance()");
90269026
},
90279027
bundleType: 0,
9028-
version: "18.3.0-next-fdad813ac-20230420",
9028+
version: "18.3.0-next-cc93a8533-20230420",
90299029
rendererPackageName: "react-test-renderer"
90309030
};
90319031
var internals$jscomp$inline_1247 = {
@@ -9056,7 +9056,7 @@ var internals$jscomp$inline_1247 = {
90569056
scheduleRoot: null,
90579057
setRefreshHandler: null,
90589058
getCurrentFiber: null,
9059-
reconcilerVersion: "18.3.0-next-fdad813ac-20230420"
9059+
reconcilerVersion: "18.3.0-next-cc93a8533-20230420"
90609060
};
90619061
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
90629062
var hook$jscomp$inline_1248 = __REACT_DEVTOOLS_GLOBAL_HOOK__;

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-dev.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-next-fdad813ac-20230420";
30+
var ReactVersion = "18.3.0-next-cc93a8533-20230420";
3131

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

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-prod.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,4 +639,4 @@ exports.useSyncExternalStore = function (
639639
);
640640
};
641641
exports.useTransition = useTransition;
642-
exports.version = "18.3.0-next-fdad813ac-20230420";
642+
exports.version = "18.3.0-next-cc93a8533-20230420";

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/cjs/React-profiling.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ exports.useSyncExternalStore = function (
642642
);
643643
};
644644
exports.useTransition = useTransition;
645-
exports.version = "18.3.0-next-fdad813ac-20230420";
645+
exports.version = "18.3.0-next-cc93a8533-20230420";
646646

647647
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
648648
if (
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
fdad813ac765e901e2957b8d36fba87e5504e5f4
1+
cc93a8533264618b7a8e3d6fb56df917214c19d7

0 commit comments

Comments
 (0)