Skip to content

[mdn] Initial experiment for adding performance tool #33045

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

Merged
merged 28 commits into from
Apr 30, 2025

Conversation

jorge-cab
Copy link
Contributor

Summary

Add a way for the agent to get some data on the performance of react code

How did you test this change?

Unit tests

console.log(result);
}, 300000);

it('should measure a component with heavy rendering load', async () => {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this test adds much value outside of slowing everything down. It might be worth having tests for the unhappy paths, for example where there's invalid syntax, imports to some unknown/non-present module, etc

Great job adding tests btw!


expect(result).toHaveProperty('renderTime');
expect(result).toHaveProperty('webVitals');
console.log(result);
Copy link
Member

Choose a reason for hiding this comment

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

nit: these console.logs can be removed before merging, they tend to clutter output

// Launch puppeteer with increased protocol timeout
const browser = await puppeteer.launch({
protocolTimeout: 600_000, // Increase timeout to 10 minutes
headless: false
Copy link
Member

Choose a reason for hiding this comment

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

Probably fine for debugging, but seems like this would be less irritating for the user if it was headless?

* @param {string} code - The source code to parse
* @returns {babel.types.File} - The parsed AST
*/
function parseAsync(code: string) {
Copy link
Member

Choose a reason for hiding this comment

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

This is already exported from babel: https://babeljs.io/docs/babel-core#parseasync. You'll also probably want to use @babel/preset-react and also tune the settings so its maximally compatible with all types of syntax since generally since we have no control over what the user is going to paste in. Might also be good to return a helpful error message if it couldn't parse / transform, since it can help the LLM adjust the syntax and try again.

One more thing you'll want to add is

  configFile: false,
  babelrc: false,

as otherwise Babel will try to look for a babel.config.js somewhere and it can throw things off.

These config options can also be shared with transformFromAstAsync I believe.

React.createElement(React.Profiler, {
id: 'App',
onRender: (id, phase, actualDuration) => {
window.__RESULT__.renderTime = actualDuration;
Copy link
Member

Choose a reason for hiding this comment

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

could probably capture all the arguments

webVitals.onTTFB((metric) => { window.__RESULT__.webVitals.ttfb = metric; });

// Wrap user code in React.Profiler to measure render performance
const renderStart = performance.now();
Copy link
Member

Choose a reason for hiding this comment

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

where's the renderEnd?

Copy link
Member

Choose a reason for hiding this comment

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

also this seems unnecessary given that React.Profiler already gives you the time taken to mount.

- First Input Delay (FID): ${performanceResults.webVitals.fid?.value || 'N/A'}ms
- Time to First Byte (TTFB): ${performanceResults.webVitals.ttfb?.value || 'N/A'}ms

These metrics can help you evaluate the performance of your React component. Lower values generally indicate better performance.
Copy link
Member

Choose a reason for hiding this comment

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

This is a nice touch. Could you try asking it to run this tool multiple times to see if it improves on these metrics?

One more thing we might want to do is to run several iterations of the test in a single tool call to reduce noise. Just using the mean for now seems like a good start.

expect(result.error).toBeNull();
}, 300000);

it('should fail due to using imported useState', async () => {
Copy link
Member

Choose a reason for hiding this comment

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

why should this fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now only because the way I'm transpiling can't deal with imports and expects everything to use React. prefix. I want to find a way around this but maybe as a forward fix because I have multiple ideas on how to do that

Copy link
Member

Choose a reason for hiding this comment

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

In that case then this is not a good test since it's only a temporary quirk and not an invariant that is necessary for correctness. I would just remove this test for now since you would have to delete it later anyway.

@jorge-cab jorge-cab marked this pull request as ready for review April 30, 2025 17:04

await page.waitForFunction(
'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)',
{timeout: 600_000},
Copy link
Member

Choose a reason for hiding this comment

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

small note but i don't think this timeout needs to be that long. If it takes over 10 seconds something is probably wrong. Feel free to address this in a follow up PR though.

@jorge-cab jorge-cab merged commit 90a124a into facebook:main Apr 30, 2025
20 checks passed
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.

4 participants