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

Refactor Component Stack Traces #18495

Merged
merged 7 commits into from
Apr 6, 2020

Conversation

sebmarkbage
Copy link
Collaborator

I'm going to play with a different way to extract prod stack traces from native stack traces as well as building Hermes specific ones. This doesn't do that yet but it's setting up some refactoring for it.

Notably this no longer uses the getComponentName helper. This means that getComponentName is now only DEV only and can be safely be DCE. Component stacks are the only way we expose names in PROD, outside of DEV tools.

This approach also relies on tag instead of a .type field existing. Some fibers don't need that type field for anything except this use case.

I also ensured to carefully wrap things in __DEV__ that removes some of the paths related to "source info" that was also included in prod even though that's no longer possible in the jsxDEV transform.

@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Apr 4, 2020
: null
: null;
const source = __DEV__ ? fiber._debugSource : null;
switch (fiber.tag) {
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 list of things that get included was kind of arbitrary and not fully consistent before because it was filtered in Fiber but not in SSR. This list seems like the most commonly useful.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Apr 4, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 5ccb1d1:

Sandbox Source
reverent-wildflower-tpdpf Configuration

let sourceInfo = '';
if (source) {
const path = source.fileName;
let fileName = path.replace(BEFORE_SLASH_RE, '');
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This should probably be wrapped in DEV.

@sizebot
Copy link

sizebot commented Apr 4, 2020

Warnings
⚠️ Base commit is broken: a387566

Size changes (experimental)

Generated by 🚫 dangerJS against 5ccb1d1

@sizebot
Copy link

sizebot commented Apr 4, 2020

Warnings
⚠️ Base commit is broken: a387566

Size changes (stable)

Generated by 🚫 dangerJS against 5ccb1d1

@sebmarkbage
Copy link
Collaborator Author

The "in StrictMode" approach doesn't really work because it doesn't apply to Concurrent and Batched mode environments which are also strict. Which we'll likely slowly adopt even in the legacy environments that are not considered modern. So I'm not sure what that is supposed to do exactly.

@gaearon
Copy link
Collaborator

gaearon commented Apr 6, 2020

We could read the current fiber’s mode and pass it from the fork.

@bvaughn
Copy link
Contributor

bvaughn commented Apr 6, 2020

Why should we expose any info about the mode though?

@sebmarkbage sebmarkbage force-pushed the proderrorstacks branch 2 times, most recently from 1ce4b9a to b1e878f Compare April 6, 2020 05:15
@sebmarkbage
Copy link
Collaborator Author

I started down an implementation like this but I don't think mode is really a generally applicable thing here. It's really arbitrary what kind of filtering you want based on your adoption strategy. Seems like some kind of explicit Context is a more appropriate approach here.

@sebmarkbage
Copy link
Collaborator Author

sebmarkbage commented Apr 6, 2020

I guess you can just add a wrapper component of any unique name and use that name as the magic string. I don't know which internal uses of StrictMode actually matters, that are not concurrent mode, so I'll let someone else do that.

@gaearon
Copy link
Collaborator

gaearon commented Apr 6, 2020

D20870861

);
});

it('should honor a displayName in stacks if set on the inner function', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will make some people unhappy. Can we make it work with the outer one too in DEV? For all the wrappers: lazy, memo, forwardRef.

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 is worse is that Firefox doesn't respect displayName in stacks at all so none of them will be respected in Firefox. However, that's also true for regular error stacks so they should just fix that there. The goal is to be no better or worse than native stacks - and ideally just like native stacks.

I don't really want to add code to parse and try to piece together a line by trying to inject a name in the middle of the browser native format somehow.

What we could do is transfer the displayName onto the inner function if one is not already defined. This would be invasive in the sense that it's mutating an object not owned by React.

Copy link
Collaborator Author

@sebmarkbage sebmarkbage Apr 6, 2020

Choose a reason for hiding this comment

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

I added a forwarding setter in DEV. 9054ad2

Not for lazy though because you're suppose to use that on the consuming side, and that's not where you specify things like propTypes or displayName. Not sure they should really be used with forwardRef/memo neither. It should really be the inner function that you name using a function expression.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ofc we had a test that reused a component. This trick doesn't work in this case. I think it's unusual though. 5449838

You can get stack from any fiber, not just current.
These should use fiber tags for switching. This also puts the relevant code
behind DEV flags.
They're not super useful and will go away later anyway.
Context is no longer part of SSR stacks. This was already the case on the
client.

forwardRef no longer is wrapped on the stack. It's still in getComponentName
but it's probably just noise in stacks. Eventually we'll remove the wrapper
so it'll go away anyway. If we use native stack frames they won't have this
extra wrapper.

It also doesn't pick up displayName from the outer wrapper. We could maybe
transfer it but this will also be fixed by removing the wrapper.
…n DEV

This allows them to show up in stack traces.

I'm not doing this for lazy because lazy is supposed to be called on the
consuming side so you shouldn't assign it a name on that end. Especially
not one that mutates the inner.
@sebmarkbage sebmarkbage force-pushed the proderrorstacks branch 2 times, most recently from afb7bc5 to 5449838 Compare April 6, 2020 22:10
We mutate the inner component for its name so we need multiple copies.
@sebmarkbage sebmarkbage merged commit 4169420 into facebook:master Apr 6, 2020
source: void | null | Source,
ownerFn: void | null | Function,
): string {
return describeFunctionComponentFrame(ctor, source, ownerFn);
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like a bug. ownerFn should not be passed directly. Why didn't Flow catch this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh. Whoops. I misread this as calling describeComponentFrame. My bad.

facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Jul 28, 2020
Summary:
In the next react sync we removed the `displayName` from forwardRef and useMemo components ([PR here](facebook/react#18495 )).

This means we need to manually add the displayName in the mock.

Changelog: [General] [Fixed] Fix test renderer mocks to use the displayName more often.

Reviewed By: TheSavior

Differential Revision: D22775470

fbshipit-source-id: 1390dc325e34f7ccea32bbdf1c6a8f6efea3a080
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants