Skip to content

Commit

Permalink
Remove invokeGuardedCallback and replay trick (#28515)
Browse files Browse the repository at this point in the history
We broke the ability to "break on uncaught exceptions" by adding a
try/catch higher up in the scheduling. We're giving up on fixing that so
we can remove the replay trick inside an event handler.

The issue with that approach is that we end up double logging a lot of
errors in DEV since they get reported to the page.

It's also a lot of complexity around this feature.

DiffTrain build for [89021fb](89021fb)
  • Loading branch information
sebmarkbage committed Mar 12, 2024
1 parent 7f3682c commit 4387423
Show file tree
Hide file tree
Showing 23 changed files with 40,887 additions and 42,979 deletions.
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
56e20051c3c1611f9495081d01f1946184332c6b
89021fb4ec9aa82194b0788566e736a4cedfc0e4
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if (__DEV__) {
) {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
}
var ReactVersion = "18.3.0-www-classic-7d5d3599";
var ReactVersion = "18.3.0-www-classic-489e33ec";

// ATTENTION
// When adding new symbols to this file,
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-prod.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -633,4 +633,4 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-www-classic-32d29ecb";
exports.version = "18.3.0-www-classic-76e5ebad";
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-profiling.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-www-classic-e14b3ab5";
exports.version = "18.3.0-www-classic-33a06df4";
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
"function" ===
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-profiling.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-www-modern-120f741e";
exports.version = "18.3.0-www-modern-dc34ad0a";
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
"function" ===
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
Expand Down
260 changes: 16 additions & 244 deletions compiled/facebook-www/ReactART-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ if (__DEV__) {
return self;
}

var ReactVersion = "18.3.0-www-classic-c7591c48";
var ReactVersion = "18.3.0-www-classic-dbf75d4c";

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -163,9 +163,7 @@ if (__DEV__) {
// Re-export dynamic flags from the www version.
var dynamicFeatureFlags = require("ReactFeatureFlags");

var replayFailedUnitOfWorkWithInvokeGuardedCallback =
dynamicFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback,
enableDebugTracing = dynamicFeatureFlags.enableDebugTracing,
var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing,
enableUseRefAccessWarning = dynamicFeatureFlags.enableUseRefAccessWarning,
enableLazyContextPropagation =
dynamicFeatureFlags.enableLazyContextPropagation,
Expand Down Expand Up @@ -3728,16 +3726,8 @@ if (__DEV__) {
}

var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches
// due to earlier mismatches or a suspended fiber.

var didSuspendOrErrorDEV = false; // Hydration errors that were thrown inside this boundary

var hydrationErrors = null;
function didSuspendOrErrorWhileHydratingDEV() {
{
return didSuspendOrErrorDEV;
}
}

function prepareToHydrateHostInstance(fiber, hostContext) {
{
Expand Down Expand Up @@ -13842,25 +13832,8 @@ if (__DEV__) {
if (true) {
var source = errorInfo.source;
var stack = errorInfo.stack;
var componentStack = stack !== null ? stack : ""; // Browsers support silencing uncaught errors by calling
// `preventDefault()` in window `error` handler.
// We record this information as an expando on the error.

if (error != null && error._suppressLogging) {
if (boundary.tag === ClassComponent) {
// The error is recoverable and was silenced.
// Ignore it and don't print the stack addendum.
// This is handy for testing error boundaries without noise.
return;
} // The error is fatal. Since the silencing might have
// been accidental, we'll surface it anyway.
// However, the browser would have silenced the original error
// so we'll print it first, and then print the stack addendum.

console["error"](error); // Don't transform to our wrapper
// For a more detailed description of this block, see:
// https://github.com/facebook/react/pull/13384
}
var componentStack = stack !== null ? stack : ""; // TODO: There's no longer a way to silence these warnings e.g. for tests.
// See https://github.com/facebook/react/pull/13384

var componentName = source ? getComponentNameFromFiber(source) : null;
var componentNameMessage = componentName
Expand All @@ -13882,19 +13855,17 @@ if (__DEV__) {
("using the error boundary you provided, " +
errorBoundaryName +
".");
}

var combinedMessage =
componentNameMessage +
"\n" +
componentStack +
"\n\n" +
("" + errorBoundaryMessage); // In development, we provide our own message with just the component stack.
// We don't include the original error message and JS stack because the browser
// has already printed it. Even if the application swallows the error, it is still
// displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils.

console["error"](combinedMessage); // Don't transform to our wrapper
} // In development, we provide our own message which includes the component stack
// in addition to the error.

console["error"](
// Don't transform to our wrapper
"%o\n\n%s\n%s\n\n%s",
error,
componentNameMessage,
componentStack,
errorBoundaryMessage
);
}
} catch (e) {
// This method must not throw, or React internal state will get messed up.
Expand Down Expand Up @@ -17942,7 +17913,7 @@ if (__DEV__) {
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}

function beginWork$1(current, workInProgress, renderLanes) {
function beginWork(current, workInProgress, renderLanes) {
{
if (workInProgress._debugNeedsRemount && current !== null) {
// This will restart the begin phase with a new fiber.
Expand Down Expand Up @@ -20738,64 +20709,6 @@ if (__DEV__) {
}
}

// Provided by www
var ReactFbErrorUtils = require("ReactFbErrorUtils");

if (typeof ReactFbErrorUtils.invokeGuardedCallback !== "function") {
throw new Error(
"Expected ReactFbErrorUtils.invokeGuardedCallback to be a function."
);
}

function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) {
// This will call `this.onError(err)` if an error was caught.
ReactFbErrorUtils.invokeGuardedCallback.apply(this, arguments);
}

var hasError = false;
var caughtError = null; // Used by event system to capture/rethrow the first error.
var reporter = {
onError: function (error) {
hasError = true;
caughtError = error;
}
};
/**
* Call a function while guarding against errors that happens within it.
* Returns an error if it throws, otherwise null.
*
* In production, this is implemented using a try-catch. The reason we don't
* use a try-catch directly is so that we can swap out a different
* implementation in DEV mode.
*
* @param {String} name of the guard to use for logging or debugging
* @param {Function} func The function to invoke
* @param {*} context The context to use when calling the function
* @param {...*} args Arguments for function
*/

function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) {
hasError = false;
caughtError = null;
invokeGuardedCallbackImpl.apply(reporter, arguments);
}
function hasCaughtError() {
return hasError;
}
function clearCaughtError() {
if (hasError) {
var error = caughtError;
hasError = false;
caughtError = null;
return error;
} else {
throw new Error(
"clearCaughtError was called but no error was captured. This error " +
"is likely caused by a bug in React. Please file an issue."
);
}
}

var didWarnAboutUndefinedSnapshotBeforeUpdate = null;

{
Expand All @@ -20818,20 +20731,6 @@ if (__DEV__) {
);
}

function reportUncaughtErrorInDEV(error) {
// Wrapping each small part of the commit phase into a guarded
// callback is a bit too slow (https://github.com/facebook/react/pull/21666).
// But we rely on it to surface errors to DEV tools like overlays
// (https://github.com/facebook/react/issues/21712).
// As a compromise, rethrow only caught errors in a guard.
{
invokeGuardedCallback(null, function () {
throw error;
});
clearCaughtError();
}
}

function callComponentWillUnmountWithTimer(current, instance) {
instance.props = current.memoizedProps;
instance.state = current.memoizedState;
Expand Down Expand Up @@ -27947,7 +27846,6 @@ if (__DEV__) {
error$1
) {
{
reportUncaughtErrorInDEV(error$1);
setIsRunningInsertionEffect(false);
}

Expand Down Expand Up @@ -28451,83 +28349,6 @@ if (__DEV__) {
}
}
}
var beginWork;

if (replayFailedUnitOfWorkWithInvokeGuardedCallback) {
var dummyFiber = null;

beginWork = function (current, unitOfWork, lanes) {
// If a component throws an error, we replay it again in a synchronously
// dispatched event, so that the debugger will treat it as an uncaught
// error See ReactErrorUtils for more information.
// Before entering the begin phase, copy the work-in-progress onto a dummy
// fiber. If beginWork throws, we'll use this to reset the state.
var originalWorkInProgressCopy = assignFiberPropertiesInDEV(
dummyFiber,
unitOfWork
);

try {
return beginWork$1(current, unitOfWork, lanes);
} catch (originalError) {
if (
didSuspendOrErrorWhileHydratingDEV() ||
originalError === SuspenseException ||
originalError === SelectiveHydrationException ||
(originalError !== null &&
typeof originalError === "object" &&
typeof originalError.then === "function")
) {
// Don't replay promises.
// Don't replay errors if we are hydrating and have already suspended or handled an error
throw originalError;
} // Don't reset current debug fiber, since we're about to work on the
// same fiber again.
// Unwind the failed stack frame

resetSuspendedWorkLoopOnUnwind(unitOfWork);
unwindInterruptedWork(current, unitOfWork); // Restore the original properties of the fiber.

assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);

if (unitOfWork.mode & ProfileMode) {
// Reset the profiler timer.
startProfilerTimer(unitOfWork);
} // Run beginWork again.

invokeGuardedCallback(
null,
beginWork$1,
null,
current,
unitOfWork,
lanes
);

if (hasCaughtError()) {
var replayError = clearCaughtError();

if (
typeof replayError === "object" &&
replayError !== null &&
replayError._suppressLogging &&
typeof originalError === "object" &&
originalError !== null &&
!originalError._suppressLogging
) {
// If suppressed, let the flag carry over to the original error which is the one we'll rethrow.
originalError._suppressLogging = true;
}
} // We always throw the original error in case the second render pass is not idempotent.
// This can happen if a memoized function or CommonJS module doesn't throw after first invocation.

throw originalError;
}
};
} else {
beginWork = beginWork$1;
}

var didWarnAboutUpdateInRender = false;
var didWarnAboutUpdateInRenderForAnotherComponent;

Expand Down Expand Up @@ -29850,55 +29671,6 @@ if (__DEV__) {
implementation: portal.implementation
};
return fiber;
} // Used for stashing WIP properties to replay failed work in DEV.

function assignFiberPropertiesInDEV(target, source) {
if (target === null) {
// This Fiber's initial properties will always be overwritten.
// We only use a Fiber to ensure the same hidden class so DEV isn't slow.
target = createFiber(IndeterminateComponent, null, null, NoMode);
} // This is intentionally written as a list of all properties.
// We tried to use Object.assign() instead but this is called in
// the hottest path, and Object.assign() was too slow:
// https://github.com/facebook/react/issues/12502
// This code is DEV-only so size is not a concern.

target.tag = source.tag;
target.key = source.key;
target.elementType = source.elementType;
target.type = source.type;
target.stateNode = source.stateNode;
target.return = source.return;
target.child = source.child;
target.sibling = source.sibling;
target.index = source.index;
target.ref = source.ref;
target.refCleanup = source.refCleanup;
target.pendingProps = source.pendingProps;
target.memoizedProps = source.memoizedProps;
target.updateQueue = source.updateQueue;
target.memoizedState = source.memoizedState;
target.dependencies = source.dependencies;
target.mode = source.mode;
target.flags = source.flags;
target.subtreeFlags = source.subtreeFlags;
target.deletions = source.deletions;
target.lanes = source.lanes;
target.childLanes = source.childLanes;
target.alternate = source.alternate;

{
target.actualDuration = source.actualDuration;
target.actualStartTime = source.actualStartTime;
target.selfBaseDuration = source.selfBaseDuration;
target.treeBaseDuration = source.treeBaseDuration;
}

target._debugInfo = source._debugInfo;
target._debugOwner = source._debugOwner;
target._debugNeedsRemount = source._debugNeedsRemount;
target._debugHookTypes = source._debugHookTypes;
return target;
}

function FiberRootNode(
Expand Down
Loading

0 comments on commit 4387423

Please sign in to comment.