11import  *  as  babel  from  '@babel/core' ; 
22import  puppeteer  from  'puppeteer' ; 
33
4- export  async  function  measurePerformance ( code : string )  { 
4+ type  PerformanceResults  =  { 
5+   renderTime : number ; 
6+   webVitals : { 
7+     cls : number ; 
8+     lcp : number ; 
9+     inp : number ; 
10+     fid : number ; 
11+     ttfb : number ; 
12+   } ; 
13+   reactProfiler : { 
14+     id : number ; 
15+     phase : number ; 
16+     actualDuration : number ; 
17+     baseDuration : number ; 
18+     startTime : number ; 
19+     commitTime : number ; 
20+   } ; 
21+   error : Error  |  null ; 
22+ } ; 
23+ 
24+ export  async  function  measurePerformance ( 
25+   code : string , 
26+   iterations : number , 
27+ ) : Promise < PerformanceResults >  { 
528  const  babelOptions  =  { 
629    configFile : false , 
730    babelrc : false , 
@@ -43,22 +66,76 @@ export async function measurePerformance(code: string) {
4366  } 
4467
4568  const  browser  =  await  puppeteer . launch ( ) ; 
46- 
4769  const  page  =  await  browser . newPage ( ) ; 
4870  await  page . setViewport ( { width : 1280 ,  height : 720 } ) ; 
4971  const  html  =  buildHtml ( transpiled ) ; 
50-   await  page . setContent ( html ,  { waitUntil : 'networkidle0' } ) ; 
5172
52-   await  page . waitForFunction ( 
53-     'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)' , 
54-   ) ; 
73+   let  performanceResults : PerformanceResults  =  { 
74+     renderTime : 0 , 
75+     webVitals : { 
76+       cls : 0 , 
77+       lcp : 0 , 
78+       inp : 0 , 
79+       fid : 0 , 
80+       ttfb : 0 , 
81+     } , 
82+     reactProfiler : { 
83+       id : 0 , 
84+       phase : 0 , 
85+       actualDuration : 0 , 
86+       baseDuration : 0 , 
87+       startTime : 0 , 
88+       commitTime : 0 , 
89+     } , 
90+     error : null , 
91+   } ; 
5592
56-   const  result  =  await  page . evaluate ( ( )  =>  { 
57-     return  ( window  as  any ) . __RESULT__ ; 
58-   } ) ; 
93+   for  ( let  ii  =  0 ;  ii  <  iterations ;  ii ++ )  { 
94+     await  page . setContent ( html ,  { waitUntil : 'networkidle0' } ) ; 
95+     await  page . waitForFunction ( 
96+       'window.__RESULT__ !== undefined && (window.__RESULT__.renderTime !== null || window.__RESULT__.error !== null)' , 
97+     ) ; 
98+     // ui chaos monkey 
99+     await  page . waitForFunction ( `window.__RESULT__ !== undefined && (function() { 
100+       for (const el of [...document.querySelectorAll('a'), ...document.querySelectorAll('button')]) { 
101+         console.log(el); 
102+         el.click(); 
103+       } 
104+       return true; 
105+     })() ` ) ; 
106+     const  evaluationResult : PerformanceResults  =  await  page . evaluate ( ( )  =>  { 
107+       return  ( window  as  any ) . __RESULT__ ; 
108+     } ) ; 
109+ 
110+     console . error ( JSON . stringify ( evaluationResult ,  null ,  2 ) ) ; 
111+ 
112+     // TODO: investigate why webvital metrics are not populating correctly 
113+     performanceResults . renderTime  +=  evaluationResult . renderTime ; 
114+     performanceResults . webVitals . cls  +=  evaluationResult . webVitals . cls  ||  0 ; 
115+     performanceResults . webVitals . lcp  +=  evaluationResult . webVitals . lcp  ||  0 ; 
116+     performanceResults . webVitals . inp  +=  evaluationResult . webVitals . inp  ||  0 ; 
117+     performanceResults . webVitals . fid  +=  evaluationResult . webVitals . fid  ||  0 ; 
118+     performanceResults . webVitals . ttfb  +=  evaluationResult . webVitals . ttfb  ||  0 ; 
119+ 
120+     performanceResults . reactProfiler . id  += 
121+       evaluationResult . reactProfiler . actualDuration  ||  0 ; 
122+     performanceResults . reactProfiler . phase  += 
123+       evaluationResult . reactProfiler . phase  ||  0 ; 
124+     performanceResults . reactProfiler . actualDuration  += 
125+       evaluationResult . reactProfiler . actualDuration  ||  0 ; 
126+     performanceResults . reactProfiler . baseDuration  += 
127+       evaluationResult . reactProfiler . baseDuration  ||  0 ; 
128+     performanceResults . reactProfiler . startTime  += 
129+       evaluationResult . reactProfiler . startTime  ||  0 ; 
130+     performanceResults . reactProfiler . commitTime  += 
131+       evaluationResult . reactProfiler . commitTime  ||  0 ; 
132+ 
133+     performanceResults . error  =  evaluationResult . error ; 
134+   } 
59135
60136  await  browser . close ( ) ; 
61-   return  result ; 
137+ 
138+   return  performanceResults ; 
62139} 
63140
64141function  buildHtml ( transpiled : string )  { 
@@ -82,7 +159,7 @@ function buildHtml(transpiled: string) {
82159                window.__RESULT__ = { 
83160                    renderTime: null, 
84161                    webVitals: {}, 
85-                     reactProfilerMetrics : {}, 
162+                     reactProfiler : {}, 
86163                    error: null 
87164                }; 
88165
@@ -112,12 +189,12 @@ function buildHtml(transpiled: string) {
112189                        React.createElement(React.Profiler, { 
113190                            id: 'App', 
114191                            onRender: (id, phase, actualDuration, baseDuration, startTime, commitTime) => { 
115-                                 window.__RESULT__.reactProfilerMetrics .id = id; 
116-                                 window.__RESULT__.reactProfilerMetrics .phase = phase; 
117-                                 window.__RESULT__.reactProfilerMetrics .actualDuration = actualDuration; 
118-                                 window.__RESULT__.reactProfilerMetrics .baseDuration = baseDuration; 
119-                                 window.__RESULT__.reactProfilerMetrics .startTime = startTime; 
120-                                 window.__RESULT__.reactProfilerMetrics .commitTime = commitTime; 
192+                                 window.__RESULT__.reactProfiler .id = id; 
193+                                 window.__RESULT__.reactProfiler .phase = phase; 
194+                                 window.__RESULT__.reactProfiler .actualDuration = actualDuration; 
195+                                 window.__RESULT__.reactProfiler .baseDuration = baseDuration; 
196+                                 window.__RESULT__.reactProfiler .startTime = startTime; 
197+                                 window.__RESULT__.reactProfiler .commitTime = commitTime; 
121198                            } 
122199                        }, React.createElement(AppComponent)) 
123200                    ); 
@@ -127,10 +204,7 @@ function buildHtml(transpiled: string) {
127204                    window.__RESULT__.renderTime = renderEnd - renderStart; 
128205                } catch (error) { 
129206                    console.error('Error rendering component:', error); 
130-                     window.__RESULT__.error = { 
131-                         message: error.message, 
132-                         stack: error.stack 
133-                     }; 
207+                     window.__RESULT__.error = error; 
134208                } 
135209            </script> 
136210            <script> 
0 commit comments