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

support errorInfo in onRecoverableError #24591

Merged
merged 9 commits into from Jun 6, 2022

Conversation

gnoff
Copy link
Collaborator

@gnoff gnoff commented May 20, 2022

errorInfo has been used in Error Boundaries wiht componentDidCatch for a while now. To date this metadata only contained a componentStack. onRecoverableError only receives an error (type mixed) argument and thus providing additional error metadata was not possible without mutating user created mixed objects.

This change modifies rootConcurrentErrors rootRecoverableErrors, and hydrationErrors so all expect CapturedValue types. additionally a new factory function allows the creation of CapturedValues from a value plus a hash and stack.

In general, client derived CapturedValues will be created using the original function which derives a componentStack from a fiber and server originated CapturedValues will be created using with a passed in hash and optional componentStack.

This PR builds on #24551 and once that is merged I will rebase this PR to clean up the diff

@sizebot
Copy link

sizebot commented May 20, 2022

Comparing: 4ddd8b4...3b86e0f

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.10% 131.54 kB 131.67 kB +0.09% 42.26 kB 42.30 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js +0.10% 136.80 kB 136.94 kB +0.10% 43.81 kB 43.85 kB
facebook-www/ReactDOM-prod.classic.js +0.09% 439.85 kB 440.25 kB +0.09% 80.44 kB 80.51 kB
facebook-www/ReactDOM-prod.modern.js +0.09% 425.14 kB 425.54 kB +0.10% 78.28 kB 78.37 kB
facebook-www/ReactDOMForked-prod.classic.js +0.09% 439.85 kB 440.25 kB +0.09% 80.45 kB 80.51 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
facebook-www/ReactDOMServer-prod.modern.js +0.43% 78.01 kB 78.34 kB +0.40% 16.35 kB 16.42 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +0.38% 34.04 kB 34.17 kB +0.44% 11.32 kB 11.37 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +0.38% 34.06 kB 34.19 kB +0.42% 11.34 kB 11.39 kB
oss-stable-semver/react-dom/umd/react-dom-server-legacy.browser.production.min.js +0.37% 34.15 kB 34.28 kB +0.32% 11.45 kB 11.49 kB
oss-stable/react-dom/umd/react-dom-server-legacy.browser.production.min.js +0.37% 34.18 kB 34.30 kB +0.31% 11.47 kB 11.51 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.production.min.js +0.37% 34.48 kB 34.61 kB +0.43% 11.49 kB 11.54 kB
oss-experimental/react-dom/umd/react-dom-server-legacy.browser.production.min.js +0.37% 34.59 kB 34.72 kB +0.37% 11.61 kB 11.65 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.production.min.js +0.34% 37.76 kB 37.89 kB +0.35% 12.52 kB 12.56 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.production.min.js +0.34% 37.79 kB 37.91 kB +0.35% 12.54 kB 12.58 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.production.min.js +0.33% 38.26 kB 38.39 kB +0.34% 12.70 kB 12.74 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.development.server.js +0.26% 62.81 kB 62.98 kB +0.14% 16.31 kB 16.34 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.development.server.js +0.26% 62.81 kB 62.98 kB +0.14% 16.31 kB 16.34 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.browser.development.server.js +0.26% 62.87 kB 63.03 kB +0.13% 16.33 kB 16.36 kB
oss-stable-semver/react-server-dom-webpack/umd/react-server-dom-webpack-writer.browser.development.server.js +0.25% 66.03 kB 66.20 kB +0.13% 16.54 kB 16.56 kB
oss-stable/react-server-dom-webpack/umd/react-server-dom-webpack-writer.browser.development.server.js +0.25% 66.03 kB 66.20 kB +0.13% 16.54 kB 16.56 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.node.development.server.js +0.25% 64.51 kB 64.67 kB +0.13% 16.47 kB 16.49 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.node.development.server.js +0.25% 64.51 kB 64.67 kB +0.13% 16.47 kB 16.49 kB
oss-experimental/react-server-dom-webpack/umd/react-server-dom-webpack-writer.browser.development.server.js +0.25% 66.09 kB 66.26 kB +0.15% 16.56 kB 16.58 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-writer.node.development.server.js +0.25% 64.56 kB 64.72 kB +0.14% 16.49 kB 16.51 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-prod.js +0.21% 257.64 kB 258.18 kB +0.26% 47.00 kB 47.12 kB
oss-stable-semver/react-art/cjs/react-art.production.min.js +0.21% 81.69 kB 81.86 kB +0.16% 25.47 kB 25.51 kB
oss-stable/react-art/cjs/react-art.production.min.js +0.21% 81.72 kB 81.89 kB +0.16% 25.47 kB 25.51 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-profiling.js +0.20% 272.71 kB 273.25 kB +0.26% 49.24 kB 49.36 kB

Generated by 🚫 dangerJS against 3b86e0f

Copy link
Collaborator

@sebmarkbage sebmarkbage left a comment

Choose a reason for hiding this comment

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

I think it looks good but would be good to double check with @acdlite.

Let's bikeshed the name of the errorHash a bit too.

onRecoverableError: (error: mixed) => void,
onRecoverableError: (
error: mixed,
errorInfo: {errorHash?: ?string, componentStack?: ?string},
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is the first place we actually name errorHash anything in a public API. It's intended to be a hash but you could use it in other ways too (including just returning the full error message in production). I wonder if we should call it something more generic?

Copy link
Collaborator

Choose a reason for hiding this comment

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

errorCode or maybe errorId?

It could be a generated ID too. Doesn't need to be a hash.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I like errorCode, feels less prescriptive than hash or id. similarly errorDigest evokes some potentially summarized error data and has analogs with crypto hashing as the output so it works kinda however you use it.

Code perhaps implies codification too much

Copy link
Collaborator

Choose a reason for hiding this comment

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

One downside of errorCode is that it's often associated with the minified error codes.

Maybe that should actually be a special field too for minified errors so you don't have to parse it yourself. Even for client errors.

(If you don't provide onError on the server and it's a React error, maybe we should use the minified error code as the default "hash" too.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So

{
  // For React errors in Prod Server or Client: the React Error Code
  code?: string,
  
  // For Server user errors: onError return value
  // For Server React errors if no onError provided: the React Error Code
  digest? string, // or whatever this name becomes
  
  // For Dev Server errors (React or user): the server component stack
  // For Dev or Prod Client errors (React or user): the client component stack
  componentStack?: string,
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sounds good. Let's do the code part later though.

@sebmarkbage sebmarkbage requested a review from acdlite May 27, 2022 18:56
const nextSibling = instance.nextSibling;
let errorMessage /*, errorComponentStack, errorHash*/;
if (
nextSibling &&
nextSibling.nodeType === ELEMENT_NODE &&
nextSibling.nodeName.toLowerCase() === 'template'
) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can probably just assume this to be the case. If not, you most likely just get an empty data set.

// if (stack !== null) errorComponentStack = stack;
return {
message: ((nextSibling: any): HTMLTemplateElement).dataset.msg,
stack: ((nextSibling: any): HTMLTemplateElement).dataset.stack,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be DEV only?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

What's your take on mode divergence on server/client? Should a prod client hitting a dev server not bubble up stacks if they are present?

Copy link
Collaborator

Choose a reason for hiding this comment

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

They should really just always be on the same mode and ideally warn if they're not.

@@ -2662,22 +2675,23 @@ function updateDehydratedSuspenseComponent(
// This boundary is in a permanent fallback state. In this case, we'll never
// get an update and we'll never be able to hydrate the final content. Let's just try the
// client side render instead.
const {errorMessage} = getSuspenseInstanceFallbackErrorDetails(
const {message, hash, stack} = getSuspenseInstanceFallbackErrorDetails(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this intermediate object get DCE?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the object ErrorDetails returns is not DCE'd but the destructuring does not create an additional object the properties just get assigned directly to local variables.

I considered 3 separate functions to return each part but that seems excessive for an error path. I also considered having ErrorDetails directly return a CapturedValue but that is pushing a new concept into ReactDOMHostConfig and I was unsure if that was wise.

How concerned are you with the object creation in ErrorDetails?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you got the tradeoff right. It's just unfortunate that Closure isn't smart enough. Seems like it should be able to.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe if you always returned the same object with the same signature at the end and just assigned to local variables before it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah I got this to work

@gnoff gnoff force-pushed the on-recoverable-error branch 2 times, most recently from c17a9ce to 553420e Compare June 2, 2022 05:47

// const stack = ((nextSibling: any): HTMLTemplateElement).dataset.stack;
// if (stack !== null) errorComponentStack = stack;
): {digest: ?string, message?: string, stack?: string} {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@sebmarkbage best way to type functions differently between DEV and prod? I could make it two functions I suppose

gnoff added 5 commits June 6, 2022 09:09
errorInfo has been used in Error Boundaries wiht componentDidCatch for a while now. To date this metadata only contained a componentStack. onRecoverableError only receives an error (type mixed) argument and thus providing additional error metadata was not possible without mutating user created mixed objects.

This change modifies rootConcurrentErrors rootRecoverableErrors, and hydrationErrors so all expect CapturedValue types. additionally a new factory function allows the creation of CapturedValues from a value plus a hash and stack.

In general, client derived CapturedValues will be created using the original function which derives a componentStack from a fiber and server originated CapturedValues will be created using with a passed in hash and optional componentStack.
@gnoff gnoff merged commit 4f29ba1 into facebook:main Jun 6, 2022
@gnoff gnoff deleted the on-recoverable-error branch June 6, 2022 21:23
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Jun 15, 2022
Summary:
This sync includes the following changes:
- **[5cc2487e0](facebook/react@5cc2487e0 )**: bump versions for next release ([#24725](facebook/react#24725)) //<Josh Story>//
- **[54f17e490](facebook/react@54f17e490 )**: [Transition Tracing] Fix Cache and Transitions Pop Order ([#24719](facebook/react#24719)) //<Luna Ruan>//
- **[7cf8dfd94](facebook/react@7cf8dfd94 )**: [Transition Tracing] Create/Process Marker Complete Callback ([#24700](facebook/react#24700)) //<Luna Ruan>//
- **[327e4a1f9](facebook/react@327e4a1f9 )**: [Follow-up] Land enableClientRenderFallbackOnTextMismatch //<Andrew Clark>//
- **[a8c9cb18b](facebook/react@a8c9cb18b )**: Land enableSuspenseLayoutEffectSemantics flag ([#24713](facebook/react#24713)) //<Andrew Clark>//
- **[a8555c308](facebook/react@a8555c308 )**: [Transition Tracing] Add Tracing Marker Stack ([#24661](facebook/react#24661)) //<Luna Ruan>//
- **[8186b1937](facebook/react@8186b1937 )**: Check for infinite update loops even if unmounted ([#24697](facebook/react#24697)) //<Andrew Clark>//
- **[060505e9d](facebook/react@060505e9d )**: Fix misapplying prod error opt-out ([#24688](facebook/react#24688)) //<Josh Story>//
- **[47944142f](facebook/react@47944142f )**: `now` isn't part of the react-reconciler config anymore ([#24689](facebook/react#24689)) //<Mathieu Dutour>//
- **[b34552352](facebook/react@b34552352 )**: [Fizz] Support abort reasons ([#24680](facebook/react#24680)) //<Josh Story>//
- **[79f54c16d](facebook/react@79f54c16d )**: Bugfix: Revealing a hidden update ([#24685](facebook/react#24685)) //<Andrew Clark>//
- **[7e8a020a4](facebook/react@7e8a020a4 )**: Remove extra Server Context argument ([#24683](facebook/react#24683)) //<Sebastian Markbåge>//
- **[4f29ba1cc](facebook/react@4f29ba1cc )**: support errorInfo in onRecoverableError ([#24591](facebook/react#24591)) //<Josh Story>//
- **[1cd90d2cc](facebook/react@1cd90d2cc )**: Refactor of interleaved ("concurrent") update queue ([#24663](facebook/react#24663)) //<Andrew Clark>//

Changelog:
[General][Changed] - React Native sync for revisions d300ceb...256aefb

jest_e2e[run_all_tests]

Reviewed By: cortinico

Differential Revision: D37155957

fbshipit-source-id: 4c0afc95abe8fa13c3803584922c8dc0059ff562
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Aug 8, 2022
Summary:
Sync goes to v18.2 release.

I had to manually trigger CircleCI builds because TTL for build artefacts is 30 days.

This sync includes the following changes:
- **[060505e9d](facebook/react@060505e9d )**: Fix misapplying prod error opt-out ([#24688](facebook/react#24688)) //<Josh Story>//
- **[47944142f](facebook/react@47944142f )**: `now` isn't part of the react-reconciler config anymore ([#24689](facebook/react#24689)) //<Mathieu Dutour>//
- **[b34552352](facebook/react@b34552352 )**: [Fizz] Support abort reasons ([#24680](facebook/react#24680)) //<Josh Story>//
- **[79f54c16d](facebook/react@79f54c16d )**: Bugfix: Revealing a hidden update ([#24685](facebook/react#24685)) //<Andrew Clark>//
- **[7e8a020a4](facebook/react@7e8a020a4 )**: Remove extra Server Context argument ([#24683](facebook/react#24683)) //<Sebastian Markbåge>//
- **[4f29ba1cc](facebook/react@4f29ba1cc )**: support errorInfo in onRecoverableError ([#24591](facebook/react#24591)) //<Josh Story>//
- **[1cd90d2cc](facebook/react@1cd90d2cc )**: Refactor of interleaved ("concurrent") update queue ([#24663](facebook/react#24663)) //<Andrew Clark>//

Changelog:
[General][Changed] - React Native sync for revisions d300ceb...9e3b772

jest_e2e[run_all_tests]

Reviewed By: JoshuaGross

Differential Revision: D38496392

fbshipit-source-id: 3ecffc2b3354104562eb23a2643fe0a37a01a7e6
roryabraham pushed a commit to Expensify/react-native that referenced this pull request Aug 17, 2022
Summary:
Sync goes to v18.2 release.

I had to manually trigger CircleCI builds because TTL for build artefacts is 30 days.

This sync includes the following changes:
- **[060505e9d](facebook/react@060505e9d )**: Fix misapplying prod error opt-out ([facebook#24688](facebook/react#24688)) //<Josh Story>//
- **[47944142f](facebook/react@47944142f )**: `now` isn't part of the react-reconciler config anymore ([facebook#24689](facebook/react#24689)) //<Mathieu Dutour>//
- **[b34552352](facebook/react@b34552352 )**: [Fizz] Support abort reasons ([facebook#24680](facebook/react#24680)) //<Josh Story>//
- **[79f54c16d](facebook/react@79f54c16d )**: Bugfix: Revealing a hidden update ([facebook#24685](facebook/react#24685)) //<Andrew Clark>//
- **[7e8a020a4](facebook/react@7e8a020a4 )**: Remove extra Server Context argument ([facebook#24683](facebook/react#24683)) //<Sebastian Markbåge>//
- **[4f29ba1cc](facebook/react@4f29ba1cc )**: support errorInfo in onRecoverableError ([facebook#24591](facebook/react#24591)) //<Josh Story>//
- **[1cd90d2cc](facebook/react@1cd90d2cc )**: Refactor of interleaved ("concurrent") update queue ([facebook#24663](facebook/react#24663)) //<Andrew Clark>//

Changelog:
[General][Changed] - React Native sync for revisions d300ceb...9e3b772

jest_e2e[run_all_tests]

Reviewed By: JoshuaGross

Differential Revision: D38496392

fbshipit-source-id: 3ecffc2b3354104562eb23a2643fe0a37a01a7e6
roryabraham pushed a commit to Expensify/react-native that referenced this pull request Aug 17, 2022
Summary:
Sync goes to v18.2 release.

I had to manually trigger CircleCI builds because TTL for build artefacts is 30 days.

This sync includes the following changes:
- **[060505e9d](facebook/react@060505e9d )**: Fix misapplying prod error opt-out ([facebook#24688](facebook/react#24688)) //<Josh Story>//
- **[47944142f](facebook/react@47944142f )**: `now` isn't part of the react-reconciler config anymore ([facebook#24689](facebook/react#24689)) //<Mathieu Dutour>//
- **[b34552352](facebook/react@b34552352 )**: [Fizz] Support abort reasons ([facebook#24680](facebook/react#24680)) //<Josh Story>//
- **[79f54c16d](facebook/react@79f54c16d )**: Bugfix: Revealing a hidden update ([facebook#24685](facebook/react#24685)) //<Andrew Clark>//
- **[7e8a020a4](facebook/react@7e8a020a4 )**: Remove extra Server Context argument ([facebook#24683](facebook/react#24683)) //<Sebastian Markbåge>//
- **[4f29ba1cc](facebook/react@4f29ba1cc )**: support errorInfo in onRecoverableError ([facebook#24591](facebook/react#24591)) //<Josh Story>//
- **[1cd90d2cc](facebook/react@1cd90d2cc )**: Refactor of interleaved ("concurrent") update queue ([facebook#24663](facebook/react#24663)) //<Andrew Clark>//

Changelog:
[General][Changed] - React Native sync for revisions d300ceb...9e3b772

jest_e2e[run_all_tests]

Reviewed By: JoshuaGross

Differential Revision: D38496392

fbshipit-source-id: 3ecffc2b3354104562eb23a2643fe0a37a01a7e6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants