Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make onUncaughtError and onCaughtError Configurable #28641

Merged
merged 7 commits into from
Mar 27, 2024

Conversation

sebmarkbage
Copy link
Collaborator

Stacked on #28627.

This makes error logging configurable using these createRoot/hydrateRoot options:

onUncaughtError(error: mixed, errorInfo: {componentStack?: ?string}) => void
onCaughtError(error: mixed, errorInfo: {componentStack?: ?string, errorBoundary?: ?React.Component<any, any>}) => void
onRecoverableError(error: mixed, errorInfo: {digest?: ?string, componentStack?: ?string}) => void

We already have the onRecoverableError option since before.

Overriding these can be used to implement custom error dialogs (with access to the componentStack).

It can also be used to silence caught errors when testing an error boundary or if you prefer not getting logs for caught errors that you've already handled in an error boundary.

I currently expose the error boundary instance but I think we should probably remove that since it doesn't make sense for non-class error boundaries and isn't very useful anyway. It's also unclear what it should do when an error is rethrown from one boundary to another.

Since these are public APIs now we can implement the ReactFiberErrorDialog forks using these options at the roots of the builds. So I unforked those files and instead passed a custom option for the native and www builds.

To do this I had to fork the ReactDOMLegacy file into ReactDOMRootFB which is a duplication but that will go away as soon as the FB fork is the only legacy root.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Mar 26, 2024
@sebmarkbage sebmarkbage force-pushed the errorcallbacksconfig branch 2 times, most recently from 5979a9a to 6b0f939 Compare March 26, 2024 04:30
@react-sizebot
Copy link

react-sizebot commented Mar 26, 2024

Comparing: 6786563...14edf65

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js +0.32% 176.06 kB 176.63 kB +0.48% 54.58 kB 54.84 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.32% 172.54 kB 173.10 kB +0.34% 53.76 kB 53.94 kB
facebook-www/ReactDOM-prod.classic.js +0.69% 588.24 kB 592.31 kB +0.41% 103.41 kB 103.83 kB
facebook-www/ReactDOM-prod.modern.js +0.25% 571.76 kB 573.20 kB +0.27% 100.45 kB 100.71 kB
test_utils/ReactAllWarnings.js Deleted 65.29 kB 0.00 kB Deleted 16.34 kB 0.00 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react-noop-renderer/cjs/react-noop-renderer.production.min.js +0.93% 15.42 kB 15.56 kB +0.51% 4.69 kB 4.71 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer.production.min.js +0.93% 15.42 kB 15.56 kB +0.51% 4.69 kB 4.71 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer.production.min.js +0.93% 15.42 kB 15.56 kB +0.51% 4.69 kB 4.71 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-persistent.production.min.js +0.93% 15.50 kB 15.64 kB +0.51% 4.70 kB 4.73 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-persistent.production.min.js +0.93% 15.50 kB 15.64 kB +0.51% 4.70 kB 4.73 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-persistent.production.min.js +0.93% 15.50 kB 15.64 kB +0.51% 4.70 kB 4.73 kB
facebook-www/ReactDOM-prod.classic.js +0.69% 588.24 kB 592.31 kB +0.41% 103.41 kB 103.83 kB
facebook-www/ReactDOM-profiling.classic.js +0.66% 617.87 kB 621.94 kB +0.39% 107.78 kB 108.20 kB
facebook-www/ReactDOMTesting-prod.classic.js +0.64% 603.02 kB 606.86 kB +0.39% 107.12 kB 107.54 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer.production.js +0.60% 35.94 kB 36.16 kB +0.28% 7.62 kB 7.65 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer.production.js +0.60% 35.94 kB 36.16 kB +0.28% 7.62 kB 7.65 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer.production.js +0.60% 35.94 kB 36.16 kB +0.28% 7.62 kB 7.65 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-persistent.production.js +0.60% 36.07 kB 36.29 kB +0.29% 7.64 kB 7.66 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-persistent.production.js +0.60% 36.07 kB 36.29 kB +0.29% 7.64 kB 7.66 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-persistent.production.js +0.60% 36.07 kB 36.29 kB +0.29% 7.64 kB 7.66 kB
facebook-www/ReactDOMTesting-dev.classic.js +0.53% 1,699.06 kB 1,708.10 kB +0.44% 337.81 kB 339.31 kB
facebook-www/ReactDOM-dev.classic.js +0.52% 1,677.54 kB 1,686.33 kB +0.43% 333.28 kB 334.72 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer.development.js +0.51% 41.99 kB 42.21 kB +0.22% 9.57 kB 9.59 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer.development.js +0.51% 41.99 kB 42.21 kB +0.22% 9.57 kB 9.59 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer.development.js +0.51% 42.10 kB 42.32 kB +0.25% 9.59 kB 9.62 kB
oss-stable-semver/react-noop-renderer/cjs/react-noop-renderer-persistent.development.js +0.51% 42.12 kB 42.34 kB +0.23% 9.59 kB 9.61 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-persistent.development.js +0.51% 42.12 kB 42.34 kB +0.23% 9.59 kB 9.61 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-persistent.development.js +0.51% 42.23 kB 42.45 kB +0.24% 9.61 kB 9.63 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.min.js +0.39% 112.74 kB 113.18 kB +0.36% 34.98 kB 35.10 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.production.min.js +0.38% 114.49 kB 114.93 kB +0.48% 35.36 kB 35.53 kB
oss-stable/react-reconciler/cjs/react-reconciler.production.min.js +0.38% 114.51 kB 114.95 kB +0.48% 35.39 kB 35.56 kB
react-native/implementations/ReactNativeRenderer-prod.js +0.37% 318.70 kB 319.87 kB +0.37% 55.82 kB 56.02 kB
react-native/implementations/ReactFabric-prod.js +0.37% 309.98 kB 311.11 kB +0.38% 54.28 kB 54.49 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.min.js +0.36% 121.79 kB 122.23 kB +0.40% 37.29 kB 37.44 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.profiling.min.js +0.36% 123.54 kB 123.98 kB +0.50% 37.72 kB 37.91 kB
oss-stable/react-reconciler/cjs/react-reconciler.profiling.min.js +0.36% 123.56 kB 124.00 kB +0.49% 37.75 kB 37.93 kB
react-native/implementations/ReactNativeRenderer-profiling.js +0.35% 337.91 kB 339.09 kB +0.36% 59.02 kB 59.24 kB
react-native/implementations/ReactFabric-profiling.js +0.34% 328.45 kB 329.58 kB +0.37% 57.34 kB 57.55 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-prod.js +0.33% 314.19 kB 315.23 kB +0.34% 55.42 kB 55.61 kB
oss-stable-semver/react-dom/umd/react-dom.production.min.js +0.33% 175.72 kB 176.29 kB +0.39% 54.87 kB 55.09 kB
oss-stable/react-dom/umd/react-dom.production.min.js +0.33% 175.79 kB 176.37 kB +0.39% 54.90 kB 55.12 kB
oss-stable-semver/react-dom/cjs/react-dom.production.min.js +0.33% 175.98 kB 176.55 kB +0.48% 54.55 kB 54.81 kB
oss-stable/react-dom/cjs/react-dom.production.min.js +0.32% 176.06 kB 176.63 kB +0.48% 54.58 kB 54.84 kB
oss-experimental/react-dom/umd/react-dom.production.min.js +0.32% 172.34 kB 172.89 kB +0.31% 54.03 kB 54.19 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.32% 172.54 kB 173.10 kB +0.34% 53.76 kB 53.94 kB
oss-experimental/react-test-renderer/umd/react-test-renderer.production.min.js +0.32% 105.08 kB 105.41 kB +0.57% 32.53 kB 32.72 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-profiling.js +0.31% 329.98 kB 331.02 kB +0.33% 57.89 kB 58.08 kB
react-native/implementations/ReactNativeRenderer-prod.fb.js +0.31% 373.25 kB 374.43 kB +0.30% 65.39 kB 65.59 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.production.min.js +0.31% 104.79 kB 105.12 kB +0.47% 32.20 kB 32.35 kB
oss-stable-semver/react-dom/umd/react-dom.profiling.min.js +0.31% 184.75 kB 185.33 kB +0.41% 57.19 kB 57.42 kB
oss-stable/react-dom/umd/react-dom.profiling.min.js +0.31% 184.83 kB 185.40 kB +0.41% 57.22 kB 57.45 kB
react-native/implementations/ReactFabric-prod.fb.js +0.31% 365.90 kB 367.03 kB +0.29% 64.10 kB 64.29 kB
oss-stable-semver/react-dom/cjs/react-dom.profiling.min.js +0.31% 185.46 kB 186.03 kB +0.42% 56.94 kB 57.17 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.production.min.js +0.31% 179.36 kB 179.91 kB +0.39% 56.26 kB 56.48 kB
oss-stable/react-dom/cjs/react-dom.profiling.min.js +0.31% 185.53 kB 186.11 kB +0.41% 56.97 kB 57.20 kB
oss-experimental/react-dom/umd/react-dom.profiling.min.js +0.31% 181.36 kB 181.92 kB +0.39% 56.33 kB 56.55 kB
oss-stable-semver/react-test-renderer/umd/react-test-renderer.production.min.js +0.31% 109.40 kB 109.73 kB +0.57% 33.73 kB 33.92 kB
oss-stable/react-test-renderer/umd/react-test-renderer.production.min.js +0.31% 109.45 kB 109.78 kB +0.55% 33.76 kB 33.95 kB
oss-experimental/react-dom/cjs/react-dom.profiling.min.js +0.30% 182.01 kB 182.56 kB +0.39% 56.10 kB 56.31 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.production.min.js +0.30% 109.12 kB 109.44 kB +0.49% 33.36 kB 33.53 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.production.min.js +0.30% 109.17 kB 109.49 kB +0.49% 33.39 kB 33.55 kB
react-native/implementations/ReactNativeRenderer-profiling.fb.js +0.29% 400.60 kB 401.77 kB +0.28% 69.66 kB 69.85 kB
react-native/implementations/ReactFabric-profiling.fb.js +0.29% 393.18 kB 394.31 kB +0.28% 68.32 kB 68.52 kB
oss-experimental/react-art/cjs/react-art.production.min.js +0.28% 98.01 kB 98.29 kB +0.46% 30.07 kB 30.21 kB
oss-stable-semver/react-art/cjs/react-art.production.min.js +0.28% 100.47 kB 100.74 kB +0.41% 30.73 kB 30.86 kB
oss-stable/react-art/cjs/react-art.production.min.js +0.28% 100.52 kB 100.80 kB +0.42% 30.76 kB 30.89 kB
facebook-www/ReactDOM-prod.modern.js +0.25% 571.76 kB 573.20 kB +0.27% 100.45 kB 100.71 kB
react-native/implementations/ReactFabric-dev.js +0.24% 971.46 kB 973.80 kB +0.13% 194.90 kB 195.15 kB
facebook-www/ReactDOM-profiling.modern.js +0.24% 601.32 kB 602.76 kB +0.26% 104.72 kB 104.99 kB
react-native/implementations/ReactNativeRenderer-dev.js +0.24% 986.35 kB 988.69 kB +0.12% 198.59 kB 198.83 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.js +0.22% 683.24 kB 684.74 kB +0.11% 150.17 kB 150.33 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.production.js +0.22% 687.43 kB 688.93 kB +0.10% 150.99 kB 151.14 kB
oss-stable/react-reconciler/cjs/react-reconciler.production.js +0.22% 687.45 kB 688.95 kB +0.10% 151.02 kB 151.17 kB
react-native/implementations/ReactFabric-dev.fb.js +0.21% 1,095.80 kB 1,098.14 kB +0.11% 217.59 kB 217.83 kB
oss-experimental/react-art/umd/react-art.production.min.js +0.21% 135.22 kB 135.50 kB +0.31% 42.17 kB 42.30 kB
react-native/implementations/ReactNativeRenderer-dev.fb.js +0.21% 1,110.41 kB 1,112.75 kB +0.11% 221.45 kB 221.70 kB
oss-stable-semver/react-art/umd/react-art.production.min.js +0.21% 137.66 kB 137.95 kB +0.27% 42.85 kB 42.97 kB
oss-stable/react-art/umd/react-art.production.min.js +0.21% 137.71 kB 138.00 kB +0.27% 42.88 kB 42.99 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.js +0.21% 724.59 kB 726.09 kB +0.10% 157.58 kB 157.74 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.profiling.js +0.21% 728.77 kB 730.27 kB +0.10% 158.40 kB 158.56 kB
oss-stable/react-reconciler/cjs/react-reconciler.profiling.js +0.21% 728.80 kB 730.30 kB +0.10% 158.43 kB 158.59 kB
oss-stable-semver/react-dom/cjs/react-dom.production.js +0.20% 943.86 kB 945.78 kB +0.08% 211.93 kB 212.11 kB
oss-stable/react-dom/cjs/react-dom.production.js +0.20% 943.88 kB 945.81 kB +0.09% 211.96 kB 212.14 kB
test_utils/ReactAllWarnings.js Deleted 65.29 kB 0.00 kB Deleted 16.34 kB 0.00 kB

Generated by 🚫 dangerJS against 14edf65

@sebmarkbage
Copy link
Collaborator Author

We don't export these default implementations so if you override them yourself, you have to reimplement them. Meaning you lose out on the reportError polyfill and the DEV only addendum that we add by default.

Copy link
Member

@rickhanlonii rickhanlonii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sick

// Caught by error boundary
if (__DEV__) {
const componentNameMessage = componentName
? `The above error occurred in the <${componentName}> component:`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this in in the same log now, does this need to say "the above error occurred in"?

Copy link
Collaborator Author

@sebmarkbage sebmarkbage Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really but it's still above within that log. I'm not sure if we want to reformat this further once we have owner stacks in DEV though since we should favor those.

I think that in that world we'd really not include this addendum at all and instead rely on the native stack traces in the console.

So I didn't think too deeply about this formatting since it'll likely go away.

`using the error boundary you provided, ${
errorBoundaryName || 'Anonymous'
}.`,
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting for myself that this will probably need a LogBox update to the regexes

global.IS_REACT_ACT_ENVIRONMENT = true;

await expect(async () => {
await act(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for myself to remember to update the act docs about throwing errors in 19

Pass the Fiber root to both as an argument.

Since for commit phase updates, we don't have access to the root until
after we schedule and update, I split the creation of class error updates
into two parts. First an object that gets scheduled and then that object
gets mutated once we've found the root.
@sebmarkbage sebmarkbage force-pushed the errorcallbacksconfig branch from bd1e511 to 3bc6080 Compare March 27, 2024 03:45
@sebmarkbage sebmarkbage force-pushed the errorcallbacksconfig branch 2 times, most recently from 49f2f7e to f01dd3d Compare March 27, 2024 04:13
@sebmarkbage sebmarkbage force-pushed the errorcallbacksconfig branch from f01dd3d to 56874ae Compare March 27, 2024 04:20
@sebmarkbage sebmarkbage force-pushed the errorcallbacksconfig branch 2 times, most recently from 358e960 to 5e04136 Compare March 27, 2024 04:36
We don't warn for the www entry point.
@sebmarkbage sebmarkbage force-pushed the errorcallbacksconfig branch from 5e04136 to 14edf65 Compare March 27, 2024 04:43
@sebmarkbage sebmarkbage merged commit a053716 into facebook:main Mar 27, 2024
38 checks passed
github-actions bot pushed a commit that referenced this pull request Mar 27, 2024
Stacked on #28627.

This makes error logging configurable using these
`createRoot`/`hydrateRoot` options:

```
onUncaughtError(error: mixed, errorInfo: {componentStack?: ?string}) => void
onCaughtError(error: mixed, errorInfo: {componentStack?: ?string, errorBoundary?: ?React.Component<any, any>}) => void
onRecoverableError(error: mixed, errorInfo: {digest?: ?string, componentStack?: ?string}) => void
```

We already have the `onRecoverableError` option since before.

Overriding these can be used to implement custom error dialogs (with
access to the `componentStack`).

It can also be used to silence caught errors when testing an error
boundary or if you prefer not getting logs for caught errors that you've
already handled in an error boundary.

I currently expose the error boundary instance but I think we should
probably remove that since it doesn't make sense for non-class error
boundaries and isn't very useful anyway. It's also unclear what it
should do when an error is rethrown from one boundary to another.

Since these are public APIs now we can implement the
ReactFiberErrorDialog forks using these options at the roots of the
builds. So I unforked those files and instead passed a custom option for
the native and www builds.

To do this I had to fork the ReactDOMLegacy file into ReactDOMRootFB
which is a duplication but that will go away as soon as the FB fork is
the only legacy root.

DiffTrain build for [a053716](a053716)
eps1lon added a commit to eps1lon/DefinitelyTyped that referenced this pull request Mar 27, 2024
eps1lon added a commit to eps1lon/DefinitelyTyped that referenced this pull request Mar 27, 2024
eps1lon added a commit to eps1lon/DefinitelyTyped that referenced this pull request Mar 27, 2024
eps1lon added a commit to eps1lon/DefinitelyTyped that referenced this pull request Mar 28, 2024
EdisonVan pushed a commit to EdisonVan/react that referenced this pull request Apr 15, 2024
Stacked on facebook#28627.

This makes error logging configurable using these
`createRoot`/`hydrateRoot` options:

```
onUncaughtError(error: mixed, errorInfo: {componentStack?: ?string}) => void
onCaughtError(error: mixed, errorInfo: {componentStack?: ?string, errorBoundary?: ?React.Component<any, any>}) => void
onRecoverableError(error: mixed, errorInfo: {digest?: ?string, componentStack?: ?string}) => void
```

We already have the `onRecoverableError` option since before.

Overriding these can be used to implement custom error dialogs (with
access to the `componentStack`).

It can also be used to silence caught errors when testing an error
boundary or if you prefer not getting logs for caught errors that you've
already handled in an error boundary.

I currently expose the error boundary instance but I think we should
probably remove that since it doesn't make sense for non-class error
boundaries and isn't very useful anyway. It's also unclear what it
should do when an error is rethrown from one boundary to another.

Since these are public APIs now we can implement the
ReactFiberErrorDialog forks using these options at the roots of the
builds. So I unforked those files and instead passed a custom option for
the native and www builds.

To do this I had to fork the ReactDOMLegacy file into ReactDOMRootFB
which is a duplication but that will go away as soon as the FB fork is
the only legacy root.
bigfootjon pushed a commit that referenced this pull request Apr 18, 2024
Stacked on #28627.

This makes error logging configurable using these
`createRoot`/`hydrateRoot` options:

```
onUncaughtError(error: mixed, errorInfo: {componentStack?: ?string}) => void
onCaughtError(error: mixed, errorInfo: {componentStack?: ?string, errorBoundary?: ?React.Component<any, any>}) => void
onRecoverableError(error: mixed, errorInfo: {digest?: ?string, componentStack?: ?string}) => void
```

We already have the `onRecoverableError` option since before.

Overriding these can be used to implement custom error dialogs (with
access to the `componentStack`).

It can also be used to silence caught errors when testing an error
boundary or if you prefer not getting logs for caught errors that you've
already handled in an error boundary.

I currently expose the error boundary instance but I think we should
probably remove that since it doesn't make sense for non-class error
boundaries and isn't very useful anyway. It's also unclear what it
should do when an error is rethrown from one boundary to another.

Since these are public APIs now we can implement the
ReactFiberErrorDialog forks using these options at the roots of the
builds. So I unforked those files and instead passed a custom option for
the native and www builds.

To do this I had to fork the ReactDOMLegacy file into ReactDOMRootFB
which is a duplication but that will go away as soon as the FB fork is
the only legacy root.

DiffTrain build for commit a053716.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team React 19
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants