From 359dddcc4e293b07a7e54b051fef8ac589dfe382 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 14:21:12 -0700 Subject: [PATCH 1/9] Fix @babel usage and remove timeouts --- .../react-mcp-server/src/utils/runtimePerf.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts index 87dae26d021b1..5ae4284a1415c 100644 --- a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts +++ b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts @@ -5,7 +5,7 @@ export async function measurePerformance(code: any) { let options = { configFile: false, babelrc: false, - presets: [['@babel/preset-env'], '@babel/preset-react'], + presets: [require.resolve('@babel/preset-env'), require.resolve('@babel/preset-react')], }; const parsed = await babel.parseAsync(code, options); @@ -14,15 +14,13 @@ export async function measurePerformance(code: any) { throw new Error('Failed to parse code'); } - const transpiled = await transformAsync(parsed); + const transpiled = await transformAsync(parsed, options); if (!transpiled) { throw new Error('Failed to transpile code'); } - const browser = await puppeteer.launch({ - protocolTimeout: 600_000, - }); + const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setViewport({width: 1280, height: 720}); @@ -30,8 +28,7 @@ export async function measurePerformance(code: any) { await page.setContent(html, {waitUntil: 'networkidle0'}); await page.waitForFunction( - 'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)', - {timeout: 600_000}, + 'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)' ); const result = await page.evaluate(() => { @@ -48,10 +45,10 @@ export async function measurePerformance(code: any) { * @param {Object} opts - Transformation options * @returns {Promise} - The transpiled code */ -async function transformAsync(ast: babel.types.Node) { +async function transformAsync(ast: babel.types.Node, options: any) { const result = await babel.transformFromAstAsync(ast, undefined, { + ...options, filename: 'file.jsx', - presets: [['@babel/preset-env'], '@babel/preset-react'], plugins: [ () => ({ visitor: { From 682fbcbdeb6d2571f92b058cbda906b11da4d830 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 14:56:58 -0700 Subject: [PATCH 2/9] Fix @babel usage and remove timeouts --- compiler/packages/react-mcp-server/src/utils/runtimePerf.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts index 5ae4284a1415c..f7ee541b29fea 100644 --- a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts +++ b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts @@ -47,7 +47,9 @@ export async function measurePerformance(code: any) { */ async function transformAsync(ast: babel.types.Node, options: any) { const result = await babel.transformFromAstAsync(ast, undefined, { - ...options, + configFile: false, + babelrc: false, + presets: [require.resolve('@babel/preset-env'), require.resolve('@babel/preset-react')], filename: 'file.jsx', plugins: [ () => ({ From 47d4fc078ea59a4a2f5080f2d80c0fe86c5ebab6 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 15:00:16 -0700 Subject: [PATCH 3/9] Minor style changes --- compiler/packages/react-mcp-server/src/utils/runtimePerf.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts index f7ee541b29fea..5ae4284a1415c 100644 --- a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts +++ b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts @@ -47,9 +47,7 @@ export async function measurePerformance(code: any) { */ async function transformAsync(ast: babel.types.Node, options: any) { const result = await babel.transformFromAstAsync(ast, undefined, { - configFile: false, - babelrc: false, - presets: [require.resolve('@babel/preset-env'), require.resolve('@babel/preset-react')], + ...options, filename: 'file.jsx', plugins: [ () => ({ From b549ec0689ddefa507ff4d40ab70e7407587e61a Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 15:00:40 -0700 Subject: [PATCH 4/9] Add more context to the tool --- compiler/packages/react-mcp-server/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/packages/react-mcp-server/src/index.ts b/compiler/packages/react-mcp-server/src/index.ts index 0aee12ccc5ad0..ea99b1b4c7b02 100644 --- a/compiler/packages/react-mcp-server/src/index.ts +++ b/compiler/packages/react-mcp-server/src/index.ts @@ -356,7 +356,7 @@ Server Components - Shift data-heavy logic to the server whenever possible. Brea server.tool( 'review-react-runtime', - 'Review the runtime of the code and get performance data to evaluate the proposed solution, the react code that is passed into this tool MUST contain an App component.', + 'Review the runtime of the code and get performance data to evaluate the proposed solution, the react code that is passed into this tool MUST contain an App functional component without arrow function. And DO NOT export anything', { text: z.string(), }, From 3141c9f501316a5426b59cb8e8e4e934e163e09a Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 15:16:42 -0700 Subject: [PATCH 5/9] Fix incorrect property access --- .../packages/react-mcp-server/src/index.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/packages/react-mcp-server/src/index.ts b/compiler/packages/react-mcp-server/src/index.ts index ea99b1b4c7b02..90051678e2079 100644 --- a/compiler/packages/react-mcp-server/src/index.ts +++ b/compiler/packages/react-mcp-server/src/index.ts @@ -387,25 +387,25 @@ server.tool( for (let i = 0; i < iterations; i++) { const performanceResults = await measurePerformance(text); perfData.renderTime += performanceResults.renderTime; - perfData.webVitals.cls += performanceResults.webVitals.cls?.value || 0; - perfData.webVitals.lcp += performanceResults.webVitals.lcp?.value || 0; - perfData.webVitals.inp += performanceResults.webVitals.inp?.value || 0; - perfData.webVitals.fid += performanceResults.webVitals.fid?.value || 0; + perfData.webVitals.cls += performanceResults.webVitals.cls || 0; + perfData.webVitals.lcp += performanceResults.webVitals.lcp || 0; + perfData.webVitals.inp += performanceResults.webVitals.inp || 0; + perfData.webVitals.fid += performanceResults.webVitals.fid || 0; perfData.webVitals.ttfb += - performanceResults.webVitals.ttfb?.value || 0; + performanceResults.webVitals.ttfb || 0; perfData.reactProfilerMetrics.id += - performanceResults.reactProfilerMetrics.actualDuration?.value || 0; + performanceResults.reactProfilerMetrics.actualDuration || 0; perfData.reactProfilerMetrics.phase += - performanceResults.reactProfilerMetrics.phase?.value || 0; + performanceResults.reactProfilerMetrics.phase || 0; perfData.reactProfilerMetrics.actualDuration += - performanceResults.reactProfilerMetrics.actualDuration?.value || 0; + performanceResults.reactProfilerMetrics.actualDuration || 0; perfData.reactProfilerMetrics.baseDuration += - performanceResults.reactProfilerMetrics.baseDuration?.value || 0; + performanceResults.reactProfilerMetrics.baseDuration || 0; perfData.reactProfilerMetrics.startTime += - performanceResults.reactProfilerMetrics.startTime?.value || 0; + performanceResults.reactProfilerMetrics.startTime || 0; perfData.reactProfilerMetrics.commitTime += - performanceResults.reactProfilerMetrics.commitTim?.value || 0; + performanceResults.reactProfilerMetrics.commitTime || 0; } const formattedResults = ` From 1900e35a38c1537a28b974a884b609cccde78104 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 15:21:30 -0700 Subject: [PATCH 6/9] prettier --- compiler/packages/react-mcp-server/src/index.ts | 3 +-- .../packages/react-mcp-server/src/utils/runtimePerf.ts | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/packages/react-mcp-server/src/index.ts b/compiler/packages/react-mcp-server/src/index.ts index 90051678e2079..2223f79ebdea5 100644 --- a/compiler/packages/react-mcp-server/src/index.ts +++ b/compiler/packages/react-mcp-server/src/index.ts @@ -391,8 +391,7 @@ server.tool( perfData.webVitals.lcp += performanceResults.webVitals.lcp || 0; perfData.webVitals.inp += performanceResults.webVitals.inp || 0; perfData.webVitals.fid += performanceResults.webVitals.fid || 0; - perfData.webVitals.ttfb += - performanceResults.webVitals.ttfb || 0; + perfData.webVitals.ttfb += performanceResults.webVitals.ttfb || 0; perfData.reactProfilerMetrics.id += performanceResults.reactProfilerMetrics.actualDuration || 0; diff --git a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts index 5ae4284a1415c..aad3da16981de 100644 --- a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts +++ b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts @@ -5,7 +5,10 @@ export async function measurePerformance(code: any) { let options = { configFile: false, babelrc: false, - presets: [require.resolve('@babel/preset-env'), require.resolve('@babel/preset-react')], + presets: [ + require.resolve('@babel/preset-env'), + require.resolve('@babel/preset-react'), + ], }; const parsed = await babel.parseAsync(code, options); @@ -28,7 +31,7 @@ export async function measurePerformance(code: any) { await page.setContent(html, {waitUntil: 'networkidle0'}); await page.waitForFunction( - 'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)' + 'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)', ); const result = await page.evaluate(() => { From 9e521516ba346616fd648817d4f9bdfe61a68f59 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 15:27:46 -0700 Subject: [PATCH 7/9] Refactor babel functions and inline them --- .../packages/react-mcp-server/src/index.ts | 6 ++- .../react-mcp-server/src/utils/runtimePerf.ts | 53 ++++++++----------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/compiler/packages/react-mcp-server/src/index.ts b/compiler/packages/react-mcp-server/src/index.ts index 2223f79ebdea5..c0265cb5926fd 100644 --- a/compiler/packages/react-mcp-server/src/index.ts +++ b/compiler/packages/react-mcp-server/src/index.ts @@ -356,7 +356,11 @@ Server Components - Shift data-heavy logic to the server whenever possible. Brea server.tool( 'review-react-runtime', - 'Review the runtime of the code and get performance data to evaluate the proposed solution, the react code that is passed into this tool MUST contain an App functional component without arrow function. And DO NOT export anything', + ` + Run this tool every time you propose a performance related change to verify if your suggestion actually improves performance. + + The react code that is passed into this tool MUST contain an App functional component without arrow function. And DO NOT export anything since we can't parse export syntax with this tool. + `, { text: z.string(), }, diff --git a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts index aad3da16981de..561b535fd2989 100644 --- a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts +++ b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts @@ -1,8 +1,8 @@ import * as babel from '@babel/core'; import puppeteer from 'puppeteer'; -export async function measurePerformance(code: any) { - let options = { +export async function measurePerformance(code: string) { + const babelOptions = { configFile: false, babelrc: false, presets: [ @@ -11,14 +11,31 @@ export async function measurePerformance(code: any) { ], }; - const parsed = await babel.parseAsync(code, options); - + // Parse the code to AST + const parsed = await babel.parseAsync(code, babelOptions); if (!parsed) { throw new Error('Failed to parse code'); } - const transpiled = await transformAsync(parsed, options); + // Transform AST to browser-compatible JavaScript + const transformResult = await babel.transformFromAstAsync(parsed, undefined, { + ...babelOptions, + filename: 'file.jsx', + plugins: [ + () => ({ + visitor: { + ImportDeclaration(path: babel.NodePath) { + const value = path.node.source.value; + if (value === 'react' || value === 'react-dom') { + path.remove(); + } + }, + }, + }), + ], + }); + const transpiled = transformResult?.code || undefined; if (!transpiled) { throw new Error('Failed to transpile code'); } @@ -42,32 +59,6 @@ export async function measurePerformance(code: any) { return result; } -/** - * Transform AST into browser-compatible JavaScript - * @param {babel.types.File} ast - The AST to transform - * @param {Object} opts - Transformation options - * @returns {Promise} - The transpiled code - */ -async function transformAsync(ast: babel.types.Node, options: any) { - const result = await babel.transformFromAstAsync(ast, undefined, { - ...options, - filename: 'file.jsx', - plugins: [ - () => ({ - visitor: { - ImportDeclaration(path: any) { - const value = path.node.source.value; - if (value === 'react' || value === 'react-dom') { - path.remove(); - } - }, - }, - }), - ], - }); - - return result?.code || ''; -} function buildHtml(transpiled: string) { const html = ` From eea64bff71a5093dd8d525955454b73a788cdc4e Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 15:31:03 -0700 Subject: [PATCH 8/9] prettier --- compiler/packages/react-mcp-server/src/utils/runtimePerf.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts index 561b535fd2989..299650fb20d17 100644 --- a/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts +++ b/compiler/packages/react-mcp-server/src/utils/runtimePerf.ts @@ -24,7 +24,9 @@ export async function measurePerformance(code: string) { plugins: [ () => ({ visitor: { - ImportDeclaration(path: babel.NodePath) { + ImportDeclaration( + path: babel.NodePath, + ) { const value = path.node.source.value; if (value === 'react' || value === 'react-dom') { path.remove(); @@ -59,7 +61,6 @@ export async function measurePerformance(code: string) { return result; } - function buildHtml(transpiled: string) { const html = ` From 6a3ca9c11c7d117434f2c6b0d97c3ddd89bb232d Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Wed, 30 Apr 2025 15:34:15 -0700 Subject: [PATCH 9/9] Fine tunning tool context --- compiler/packages/react-mcp-server/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/packages/react-mcp-server/src/index.ts b/compiler/packages/react-mcp-server/src/index.ts index c0265cb5926fd..657acc542b566 100644 --- a/compiler/packages/react-mcp-server/src/index.ts +++ b/compiler/packages/react-mcp-server/src/index.ts @@ -359,7 +359,10 @@ server.tool( ` Run this tool every time you propose a performance related change to verify if your suggestion actually improves performance. - The react code that is passed into this tool MUST contain an App functional component without arrow function. And DO NOT export anything since we can't parse export syntax with this tool. + This tool has some requirements on the code input: + - The react code that is passed into this tool MUST contain an App functional component without arrow function. + - DO NOT export anything since we can't parse export syntax with this tool. + - Only import React from 'react' and use all hooks and imports using the React. prefix like React.useState and React.useEffect `, { text: z.string(),