Skip to content

Run Component Track Logs in the console.createTask() of the Fiber #32809

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

sebmarkbage
Copy link
Collaborator

@sebmarkbage sebmarkbage commented Apr 2, 2025

Stacked on #32736.

That way you can find the owner stack of each component that rerendered for context.

In addition to the JSX callsite tasks that we already track, I also added tracking of the first setState call before rendering.

We then run the "Update" entries in that task. That way you can find the callsite of the first setState and therefore the "cause" of a render starting by selecting the "Update" track.

Unfortunately this is blocked on bugs in Chrome that makes it so that these stacks are not reliable in the Performance tab. It basically just doesn't work.

@react-sizebot
Copy link

react-sizebot commented Apr 2, 2025

Comparing: 17f88c8...973f98f

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.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 518.75 kB 518.75 kB = 92.26 kB 92.26 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 624.61 kB 624.61 kB = 110.44 kB 110.44 kB
facebook-www/ReactDOM-prod.classic.js = 658.01 kB 658.01 kB = 115.99 kB 115.99 kB
facebook-www/ReactDOM-prod.modern.js = 648.29 kB 648.29 kB = 114.44 kB 114.44 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-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js +0.85% 106.45 kB 107.36 kB = 20.40 kB 20.39 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js +0.85% 106.81 kB 107.72 kB = 20.34 kB 20.33 kB
oss-experimental/react-client/cjs/react-client-flight.development.js +0.84% 108.10 kB 109.01 kB +0.04% 20.16 kB 20.17 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +0.84% 108.64 kB 109.54 kB = 20.79 kB 20.78 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +0.83% 109.19 kB 110.10 kB = 20.93 kB 20.91 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js +0.82% 110.53 kB 111.44 kB = 21.15 kB 21.13 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js +0.82% 111.05 kB 111.96 kB = 21.17 kB 21.16 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js +0.81% 112.34 kB 113.24 kB = 21.51 kB 21.49 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js +0.80% 113.69 kB 114.59 kB = 21.65 kB 21.64 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js +0.79% 115.43 kB 116.34 kB = 22.01 kB 21.99 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js +0.79% 115.52 kB 116.43 kB = 22.04 kB 22.03 kB
oss-experimental/react-art/cjs/react-art.development.js +0.78% 652.79 kB 657.91 kB +0.49% 103.46 kB 103.97 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.unbundled.development.js +0.78% 116.43 kB 117.34 kB = 21.92 kB 21.91 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js +0.77% 117.76 kB 118.67 kB = 22.18 kB 22.16 kB
facebook-www/ReactART-dev.modern.js +0.73% 706.04 kB 711.19 kB +0.44% 110.29 kB 110.77 kB
facebook-www/ReactART-dev.classic.js +0.72% 715.54 kB 720.68 kB +0.41% 112.14 kB 112.60 kB
oss-experimental/react-reconciler/cjs/react-reconciler.development.js +0.65% 776.71 kB 781.76 kB +0.36% 121.99 kB 122.43 kB
facebook-www/ReactReconciler-dev.modern.js +0.61% 817.20 kB 822.20 kB +0.42% 127.60 kB 128.13 kB
facebook-www/ReactReconciler-dev.classic.js +0.61% 826.40 kB 831.40 kB +0.41% 129.32 kB 129.86 kB
oss-experimental/react-dom/cjs/react-dom-client.development.js +0.44% 1,133.66 kB 1,138.65 kB +0.30% 189.20 kB 189.76 kB
oss-experimental/react-dom/cjs/react-dom-profiling.development.js +0.43% 1,150.05 kB 1,155.05 kB +0.29% 192.04 kB 192.61 kB
oss-experimental/react-dom/cjs/react-dom-unstable_testing.development.js +0.43% 1,150.20 kB 1,155.20 kB +0.29% 192.88 kB 193.44 kB
facebook-www/ReactDOM-dev.modern.js +0.42% 1,187.73 kB 1,192.67 kB +0.30% 196.90 kB 197.49 kB
facebook-www/ReactDOM-dev.classic.js +0.41% 1,196.87 kB 1,201.81 kB +0.29% 198.67 kB 199.24 kB
facebook-www/ReactDOMTesting-dev.modern.js +0.41% 1,204.26 kB 1,209.20 kB +0.27% 200.72 kB 201.26 kB
facebook-www/ReactDOMTesting-dev.classic.js +0.41% 1,213.40 kB 1,218.34 kB +0.27% 202.42 kB 202.96 kB
facebook-www/ReactDOM-profiling.classic.js = 729.44 kB 725.71 kB = 125.99 kB 125.23 kB
facebook-www/ReactDOM-profiling.modern.js = 721.39 kB 717.67 kB = 124.69 kB 123.92 kB
oss-experimental/react-dom/cjs/react-dom-profiling.profiling.js = 688.76 kB 684.93 kB = 120.19 kB 119.43 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.js = 528.10 kB 524.15 kB = 83.67 kB 82.84 kB

Generated by 🚫 dangerJS against 973f98f

@@ -3596,7 +3596,7 @@ function dispatchSetState<S, A>(
lane,
);
if (didScheduleUpdate) {
startUpdateTimerByLane(lane);
startUpdateTimerByLane(lane, 'setState()');
Copy link
Member

Choose a reason for hiding this comment

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

omg yes

Copy link
Collaborator

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

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

That way you can find the callsite of the first setState and therefore the "cause" of a render starting by selecting the "Update" track.

Big.

Can we do the same for render()? I only know of render() calls from within components for trivial trees like screen reader announcements so maybe not that important.

Is it possible to attach an Owner Stack to changes in sync external Stores?

LANES_TRACK_GROUP,
'primary-dark',
);
// TODO: Ideally this would use the debugTask of the startTransition call perhaps.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Right now it's using the one from the setState call that was wrapped in startTransition, right?

If I had to choose, I'd usually prefer the deeper one. Does createTask include the async stack? If not, you could set a breakpoint at the setState and find the corresponding startTransition that way if it's async. If the transition function is sync, having the deeper setState task is already perfect IMO.

The task for startTransition could leave you hanging if the transition function has multiple setState (maybe even in separate if-else).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yea. I was thinking about maybe starting to log the Event and Action entries inside the setState call itself instead of waiting for the render to start. That way it would have the stack trace of the setState even in the profiling builds which would not have createTask enabled if the console.timeStamp call itself had it natively. The downside is that the "Update" track would not have it since it gets logged at the end time.

However, we can also just use createTask in profiling builds just for this case since it's just once per setState and cheap when DevTools is not open.

@@ -1861,6 +1863,7 @@ function subscribeToStore<T>(
// read from the store.
if (checkIfSnapshotChanged(inst)) {
// Force a re-render.
startUpdateTimerByLane(SyncLane, 'updateSyncExternalStore()');
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice

Except for errors in DEV where we use the properties extension.
If we use the same start/end time we get the same effect.
…Task

This ensures that we can get the owner stack of the currently rendering
component when it emits its profiling information.
We then run the "Update" entries in that task.

That way you can find the callsite of the first setState and therefore the
"cause" of a render starting.
Ideally we'd show the whole failed subtree including the errored Component.
We have the metrics for it. We just need to stash the Fibers somewhere.

In the meantime we just change the stack trace of the error boundary entry.
There's no API called this we just call it callback() but to give some hint.
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