@samitouri / QOS-React-2 / commits / 0ba0564aee

[DevTools] Add utils for perfomance marks (#22180)

Juan committed Aug 26, 2021 at 13:05 UTC 0ba0564aeea73b496264b6b2031b990a783cc142
3 files changed +240 -292
packages/react-devtools-extensions/src/astUtils.js
+28 -50
@@ -7,7 +7,7 @@
7 * @flow
8 */
9
10 -import {__PERFORMANCE_PROFILE__} from 'react-devtools-shared/src/constants';
10 +import {withSyncPerformanceMark} from 'react-devtools-shared/src/PerformanceMarks';
11 import traverse, {NodePath, Node} from '@babel/traverse';
12 import {File} from '@babel/types';
13
@@ -28,15 +28,6 @@ export type SourceFileASTWithHookDetails = {
28
29 export const NO_HOOK_NAME = '<no-hook>';
30
31 -function mark(markName: string): void {
32 - performance.mark(markName + '-start');
33 -}
34 -
35 -function measure(markName: string): void {
36 - performance.mark(markName + '-end');
37 - performance.measure(markName, markName + '-start', markName + '-end');
38 -}
39 -
31 const AST_NODE_TYPES = Object.freeze({
32 PROGRAM: 'Program',
33 CALL_EXPRESSION: 'CallExpression',
@@ -141,13 +132,10 @@ export function getHookName(
132 originalSourceLineNumber: number,
133 originalSourceColumnNumber: number,
134 ): string | null {
144 - if (__PERFORMANCE_PROFILE__) {
145 - mark('getPotentialHookDeclarationsFromAST(originalSourceAST)');
146 - }
147 - const hooksFromAST = getPotentialHookDeclarationsFromAST(originalSourceAST);
148 - if (__PERFORMANCE_PROFILE__) {
149 - measure('getPotentialHookDeclarationsFromAST(originalSourceAST)');
150 - }
135 + const hooksFromAST = withSyncPerformanceMark(
136 + 'getPotentialHookDeclarationsFromAST(originalSourceAST)',
137 + () => getPotentialHookDeclarationsFromAST(originalSourceAST),
138 + );
139
140 let potentialReactHookASTNode = null;
141 if (originalSourceColumnNumber === 0) {
@@ -188,29 +176,23 @@ export function getHookName(
176 // nodesAssociatedWithReactHookASTNode could directly be used to obtain the hook variable name
177 // depending on the type of potentialReactHookASTNode
178 try {
191 - if (__PERFORMANCE_PROFILE__) {
192 - mark('getFilteredHookASTNodes()');
193 - }
194 - const nodesAssociatedWithReactHookASTNode = getFilteredHookASTNodes(
195 - potentialReactHookASTNode,
196 - hooksFromAST,
197 - originalSourceCode,
179 + const nodesAssociatedWithReactHookASTNode = withSyncPerformanceMark(
180 + 'getFilteredHookASTNodes()',
181 + () =>
182 + getFilteredHookASTNodes(
183 + potentialReactHookASTNode,
184 + hooksFromAST,
185 + originalSourceCode,
186 + ),
187 );
199 - if (__PERFORMANCE_PROFILE__) {
200 - measure('getFilteredHookASTNodes()');
201 - }
188
203 - if (__PERFORMANCE_PROFILE__) {
204 - mark('getHookNameFromNode()');
205 - }
206 - const name = getHookNameFromNode(
207 - hook,
208 - nodesAssociatedWithReactHookASTNode,
209 - potentialReactHookASTNode,
189 + const name = withSyncPerformanceMark('getHookNameFromNode()', () =>
190 + getHookNameFromNode(
191 + hook,
192 + nodesAssociatedWithReactHookASTNode,
193 + potentialReactHookASTNode,
194 + ),
195 );
211 - if (__PERFORMANCE_PROFILE__) {
212 - measure('getHookNameFromNode()');
213 - }
196
197 return name;
198 } catch (error) {
@@ -315,19 +297,15 @@ function getHookVariableName(
297
298 function getPotentialHookDeclarationsFromAST(sourceAST: File): NodePath[] {
299 const potentialHooksFound: NodePath[] = [];
318 - if (__PERFORMANCE_PROFILE__) {
319 - mark('traverse(sourceAST)');
320 - }
321 - traverse(sourceAST, {
322 - enter(path) {
323 - if (path.isVariableDeclarator() && isPotentialHookDeclaration(path)) {
324 - potentialHooksFound.push(path);
325 - }
326 - },
327 - });
328 - if (__PERFORMANCE_PROFILE__) {
329 - measure('traverse(sourceAST)');
330 - }
300 + withSyncPerformanceMark('traverse(sourceAST)', () =>
301 + traverse(sourceAST, {
302 + enter(path) {
303 + if (path.isVariableDeclarator() && isPotentialHookDeclaration(path)) {
304 + potentialHooksFound.push(path);
305 + }
306 + },
307 + }),
308 + );
309 return potentialHooksFound;
310 }
311
packages/react-devtools-extensions/src/parseHookNames/parseHookNames.js
+153 -242
@@ -12,13 +12,15 @@ import LRU from 'lru-cache';
12 import {SourceMapConsumer} from 'source-map-js';
13 import {getHookName} from '../astUtils';
14 import {areSourceMapsAppliedToErrors} from '../ErrorTester';
15 -import {
16 - __DEBUG__,
17 - __PERFORMANCE_PROFILE__,
18 -} from 'react-devtools-shared/src/constants';
15 +import {__DEBUG__} from 'react-devtools-shared/src/constants';
16 import {getHookSourceLocationKey} from 'react-devtools-shared/src/hookNamesCache';
17 import {sourceMapIncludesSource} from '../SourceMapUtils';
18 import {SourceMapMetadataConsumer} from '../SourceMapMetadataConsumer';
19 +import {
20 + withAsyncPerformanceMark,
21 + withCallbackPerformanceMark,
22 + withSyncPerformanceMark,
23 +} from 'react-devtools-shared/src/PerformanceMarks';
24
25 import type {
26 HooksNode,
@@ -26,18 +28,8 @@ import type {
28 HooksTree,
29 } from 'react-debug-tools/src/ReactDebugHooks';
30 import type {HookNames, LRUCache} from 'react-devtools-shared/src/types';
29 -import type {Thenable} from 'shared/ReactTypes';
31 import type {SourceConsumer} from '../astUtils';
32
32 -function mark(markName: string): void {
33 - performance.mark(markName + '-start');
34 -}
35 -
36 -function measure(markName: string): void {
37 - performance.mark(markName + '-end');
38 - performance.measure(markName, markName + '-start', markName + '-end');
39 -}
40 -
33 const MAX_SOURCE_LENGTH = 100_000_000;
34
35 type AST = mixed;
@@ -118,17 +110,20 @@ const originalURLToMetadataCache: LRUCache<
110
111 export async function parseHookNames(
112 hooksTree: HooksTree,
121 -): Thenable<HookNames | null> {
122 - if (__PERFORMANCE_PROFILE__) {
123 - mark('parseHookNames()');
124 - mark('flattenHooksList()');
125 - }
113 +): Promise<HookNames | null> {
114 const hooksList: Array<HooksNode> = [];
127 - flattenHooksList(hooksTree, hooksList);
128 - if (__PERFORMANCE_PROFILE__) {
129 - measure('flattenHooksList()');
130 - }
115 + withSyncPerformanceMark('flattenHooksList()', () => {
116 + flattenHooksList(hooksTree, hooksList);
117 + });
118 +
119 + return withAsyncPerformanceMark('parseHookNames()', () =>
120 + parseHookNamesImpl(hooksList),
121 + );
122 +}
123
124 +async function parseHookNamesImpl(
125 + hooksList: HooksNode[],
126 +): Promise<HookNames | null> {
127 if (__DEBUG__) {
128 console.log('parseHookNames() hooksList:', hooksList);
129 }
@@ -183,56 +178,25 @@ export async function parseHookNames(
178 }
179 }
180
186 - if (__PERFORMANCE_PROFILE__) {
187 - mark('loadSourceFiles()');
188 - }
181 + await withAsyncPerformanceMark('loadSourceFiles()', () =>
182 + loadSourceFiles(locationKeyToHookSourceData),
183 + );
184
190 - let promise = loadSourceFiles(locationKeyToHookSourceData);
191 - if (__PERFORMANCE_PROFILE__) {
192 - promise = promise.then(data => {
193 - mark('extractAndLoadSourceMaps()');
194 - measure('loadSourceFiles()');
195 - return data;
196 - });
197 - }
198 - promise = promise.then(() =>
185 + await withAsyncPerformanceMark('extractAndLoadSourceMaps()', () =>
186 extractAndLoadSourceMaps(locationKeyToHookSourceData),
187 );
201 - if (__PERFORMANCE_PROFILE__) {
202 - promise = promise.then(data => {
203 - mark('parseSourceAST()');
204 - measure('extractAndLoadSourceMaps()');
205 - return data;
206 - });
207 - }
208 - promise = promise.then(() => parseSourceAST(locationKeyToHookSourceData));
209 - if (__PERFORMANCE_PROFILE__) {
210 - promise = promise.then(data => {
211 - mark('updateLruCache()');
212 - measure('parseSourceAST()');
213 - return data;
214 - });
215 - }
216 - promise = promise.then(() => updateLruCache(locationKeyToHookSourceData));
217 - if (__PERFORMANCE_PROFILE__) {
218 - promise = promise.then(data => {
219 - mark('findHookNames()');
220 - measure('updateLruCache()');
221 - return data;
222 - });
223 - }
224 - promise = promise.then(() =>
225 - findHookNames(hooksList, locationKeyToHookSourceData),
188 +
189 + withSyncPerformanceMark('parseSourceAST()', () =>
190 + parseSourceAST(locationKeyToHookSourceData),
191 );
227 - if (__PERFORMANCE_PROFILE__) {
228 - promise = promise.then(data => {
229 - measure('findHookNames()');
230 - measure('parseHookNames()');
231 - return data;
232 - });
233 - }
192
235 - return promise;
193 + withSyncPerformanceMark('updateLruCache()', () =>
194 + updateLruCache(locationKeyToHookSourceData),
195 + );
196 +
197 + return withSyncPerformanceMark('findHookNames()', () =>
198 + findHookNames(hooksList, locationKeyToHookSourceData),
199 + );
200 }
201
202 function decodeBase64String(encoded: string): Object {
@@ -279,13 +243,10 @@ function extractAndLoadSourceMaps(
243 const sourceMapRegex = / ?sourceMappingURL=([^\s'"]+)/gm;
244 const runtimeSourceCode = ((hookSourceData.runtimeSourceCode: any): string);
245
282 - if (__PERFORMANCE_PROFILE__) {
283 - mark('sourceMapRegex.exec(runtimeSourceCode)');
284 - }
285 - let sourceMappingURLMatch = sourceMapRegex.exec(runtimeSourceCode);
286 - if (__PERFORMANCE_PROFILE__) {
287 - measure('sourceMapRegex.exec(runtimeSourceCode)');
288 - }
246 + let sourceMappingURLMatch = withSyncPerformanceMark(
247 + 'sourceMapRegex.exec(runtimeSourceCode)',
248 + () => sourceMapRegex.exec(runtimeSourceCode),
249 + );
250
251 if (sourceMappingURLMatch == null) {
252 // Maybe file has not been transformed; we'll try to parse it as-is in parseSourceAST().
@@ -309,21 +270,13 @@ function extractAndLoadSourceMaps(
270 const trimmed = ((sourceMappingURL.match(
271 /base64,([a-zA-Z0-9+\/=]+)/,
272 ): any): Array<string>)[1];
312 - if (__PERFORMANCE_PROFILE__) {
313 - mark('decodeBase64String()');
314 - }
315 - const decoded = decodeBase64String(trimmed);
316 - if (__PERFORMANCE_PROFILE__) {
317 - measure('decodeBase64String()');
318 - }
273 + const decoded = withSyncPerformanceMark('decodeBase64String()', () =>
274 + decodeBase64String(trimmed),
275 + );
276
320 - if (__PERFORMANCE_PROFILE__) {
321 - mark('JSON.parse(decoded)');
322 - }
323 - const parsed = JSON.parse(decoded);
324 - if (__PERFORMANCE_PROFILE__) {
325 - measure('JSON.parse(decoded)');
326 - }
277 + const parsed = withSyncPerformanceMark('JSON.parse(decoded)', () =>
278 + JSON.parse(decoded),
279 + );
280
281 if (__DEBUG__) {
282 console.groupCollapsed(
@@ -336,27 +289,24 @@ function extractAndLoadSourceMaps(
289 // Hook source might be a URL like "https://4syus.csb.app/src/App.js"
290 // Parsed source map might be a partial path like "src/App.js"
291 if (sourceMapIncludesSource(parsed, runtimeSourceURL)) {
339 - if (__PERFORMANCE_PROFILE__) {
340 - mark('new SourceMapMetadataConsumer(parsed)');
341 - }
342 - hookSourceData.metadataConsumer = new SourceMapMetadataConsumer(
343 - parsed,
292 + hookSourceData.metadataConsumer = withSyncPerformanceMark(
293 + 'new SourceMapMetadataConsumer(parsed)',
294 + () => new SourceMapMetadataConsumer(parsed),
295 + );
296 + hookSourceData.sourceConsumer = withSyncPerformanceMark(
297 + 'new SourceMapConsumer(parsed)',
298 + () => new SourceMapConsumer(parsed),
299 );
345 - if (__PERFORMANCE_PROFILE__) {
346 - measure('new SourceMapMetadataConsumer(parsed)');
347 - mark('new SourceMapConsumer(parsed)');
348 - }
349 - hookSourceData.sourceConsumer = new SourceMapConsumer(parsed);
350 - if (__PERFORMANCE_PROFILE__) {
351 - measure('new SourceMapConsumer(parsed)');
352 - }
300 break;
301 }
302 } else {
303 externalSourceMapURLs.push(sourceMappingURL);
304 }
305
359 - sourceMappingURLMatch = sourceMapRegex.exec(runtimeSourceCode);
306 + sourceMappingURLMatch = withSyncPerformanceMark(
307 + 'sourceMapRegex.exec(runtimeSourceCode)',
308 + () => sourceMapRegex.exec(runtimeSourceCode),
309 + );
310 }
311
312 const foundInlineSourceMap =
@@ -395,29 +345,20 @@ function extractAndLoadSourceMaps(
345 fetchPromises.get(url) ||
346 fetchFile(url).then(
347 sourceMapContents => {
398 - if (__PERFORMANCE_PROFILE__) {
399 - mark('JSON.parse(sourceMapContents)');
400 - }
401 - const parsed = JSON.parse(sourceMapContents);
402 - if (__PERFORMANCE_PROFILE__) {
403 - measure('JSON.parse(sourceMapContents)');
404 - }
348 + const parsed = withSyncPerformanceMark(
349 + 'JSON.parse(sourceMapContents)',
350 + () => JSON.parse(sourceMapContents),
351 + );
352
406 - if (__PERFORMANCE_PROFILE__) {
407 - mark('SourceMapConsumer(parsed)');
408 - }
409 - const sourceConsumer = new SourceMapConsumer(parsed);
410 - if (__PERFORMANCE_PROFILE__) {
411 - measure('SourceMapConsumer(parsed)');
412 - }
353 + const sourceConsumer = withSyncPerformanceMark(
354 + 'new SourceMapConsumer(parsed)',
355 + () => new SourceMapConsumer(parsed),
356 + );
357
414 - if (__PERFORMANCE_PROFILE__) {
415 - mark('SourceMapMetadataConsumer(parsed)');
416 - }
417 - const metadataConsumer = new SourceMapMetadataConsumer(parsed);
418 - if (__PERFORMANCE_PROFILE__) {
419 - measure('SourceMapMetadataConsumer(parsed)');
420 - }
358 + const metadataConsumer = withSyncPerformanceMark(
359 + 'new SourceMapMetadataConsumer(parsed)',
360 + () => new SourceMapMetadataConsumer(parsed),
361 + );
362
363 return {sourceConsumer, metadataConsumer};
364 },
@@ -451,51 +392,43 @@ function extractAndLoadSourceMaps(
392 }
393
394 function fetchFile(url: string): Promise<string> {
454 - if (__PERFORMANCE_PROFILE__) {
455 - mark('fetchFile("' + url + '")');
456 - }
457 -
458 - return new Promise((resolve, reject) => {
459 - fetch(url).then(
460 - response => {
461 - if (response.ok) {
462 - response
463 - .text()
464 - .then(text => {
465 - if (__PERFORMANCE_PROFILE__) {
466 - measure('fetchFile("' + url + '")');
467 - }
468 - resolve(text);
469 - })
470 - .catch(error => {
471 - if (__DEBUG__) {
472 - console.log(`fetchFile() Could not read text for url "${url}"`);
473 - }
474 - if (__PERFORMANCE_PROFILE__) {
475 - measure('fetchFile("' + url + '")');
476 - }
477 - reject(null);
478 - });
479 - } else {
480 - if (__DEBUG__) {
481 - console.log(`fetchFile() Got bad response for url "${url}"`);
395 + return withCallbackPerformanceMark('fetchFile("' + url + '")', done => {
396 + return new Promise((resolve, reject) => {
397 + fetch(url).then(
398 + response => {
399 + if (response.ok) {
400 + response
401 + .text()
402 + .then(text => {
403 + done();
404 + resolve(text);
405 + })
406 + .catch(error => {
407 + if (__DEBUG__) {
408 + console.log(
409 + `fetchFile() Could not read text for url "${url}"`,
410 + );
411 + }
412 + done();
413 + reject(null);
414 + });
415 + } else {
416 + if (__DEBUG__) {
417 + console.log(`fetchFile() Got bad response for url "${url}"`);
418 + }
419 + done();
420 + reject(null);
421 }
483 - if (__PERFORMANCE_PROFILE__) {
484 - measure('fetchFile("' + url + '")');
422 + },
423 + error => {
424 + if (__DEBUG__) {
425 + console.log(`fetchFile() Could not fetch file: ${error.message}`);
426 }
427 + done();
428 reject(null);
487 - }
488 - },
489 - error => {
490 - if (__DEBUG__) {
491 - console.log(`fetchFile() Could not fetch file: ${error.message}`);
492 - }
493 - if (__PERFORMANCE_PROFILE__) {
494 - measure('fetchFile("' + url + '")');
495 - }
496 - reject(null);
497 - },
498 - );
429 + },
430 + );
431 + });
432 });
433 }
434
@@ -535,20 +468,18 @@ function findHookNames(
468 originalSourceColumnNumber = columnNumber;
469 originalSourceLineNumber = lineNumber;
470 } else {
538 - if (__PERFORMANCE_PROFILE__) {
539 - mark('sourceConsumer.originalPositionFor()');
540 - }
541 - const position = sourceConsumer.originalPositionFor({
542 - line: lineNumber,
543 -
544 - // Column numbers are represented differently between tools/engines.
545 - // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based.
546 - // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991
547 - column: columnNumber - 1,
548 - });
549 - if (__PERFORMANCE_PROFILE__) {
550 - measure('sourceConsumer.originalPositionFor()');
551 - }
471 + const position = withSyncPerformanceMark(
472 + 'sourceConsumer.originalPositionFor()',
473 + () =>
474 + sourceConsumer.originalPositionFor({
475 + line: lineNumber,
476 +
477 + // Column numbers are represented differently between tools/engines.
478 + // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based.
479 + // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991
480 + column: columnNumber - 1,
481 + }),
482 + );
483
484 originalSourceColumnNumber = position.column;
485 originalSourceLineNumber = position.line;
@@ -571,33 +502,25 @@ function findHookNames(
502 let name;
503 const {metadataConsumer} = hookSourceData;
504 if (metadataConsumer != null) {
574 - if (__PERFORMANCE_PROFILE__) {
575 - mark('metadataConsumer.hookNameFor()');
576 - }
577 - name = metadataConsumer.hookNameFor({
578 - line: originalSourceLineNumber,
579 - column: originalSourceColumnNumber,
580 - source: originalSourceURL,
581 - });
582 - if (__PERFORMANCE_PROFILE__) {
583 - measure('metadataConsumer.hookNameFor()');
584 - }
505 + name = withSyncPerformanceMark('metadataConsumer.hookNameFor()', () =>
506 + metadataConsumer.hookNameFor({
507 + line: originalSourceLineNumber,
508 + column: originalSourceColumnNumber,
509 + source: originalSourceURL,
510 + }),
511 + );
512 }
513
514 if (name == null) {
588 - if (__PERFORMANCE_PROFILE__) {
589 - mark('getHookName()');
590 - }
591 - name = getHookName(
592 - hook,
593 - hookSourceData.originalSourceAST,
594 - ((hookSourceData.originalSourceCode: any): string),
595 - ((originalSourceLineNumber: any): number),
596 - originalSourceColumnNumber,
515 + name = withSyncPerformanceMark('getHookName()', () =>
516 + getHookName(
517 + hook,
518 + hookSourceData.originalSourceAST,
519 + ((hookSourceData.originalSourceCode: any): string),
520 + ((originalSourceLineNumber: any): number),
521 + originalSourceColumnNumber,
522 + ),
523 );
598 - if (__PERFORMANCE_PROFILE__) {
599 - measure('getHookName()');
600 - }
524 }
525
526 if (__DEBUG__) {
@@ -645,9 +568,9 @@ function loadSourceFiles(
568 return Promise.all(setPromises);
569 }
570
648 -async function parseSourceAST(
571 +function parseSourceAST(
572 locationKeyToHookSourceData: Map<string, HookSourceData>,
650 -): Promise<*> {
573 +): void {
574 locationKeyToHookSourceData.forEach(hookSourceData => {
575 if (hookSourceData.originalSourceAST !== null) {
576 // Use cached metadata.
@@ -665,22 +588,20 @@ async function parseSourceAST(
588 if (lineNumber == null || columnNumber == null) {
589 throw Error('Hook source code location not found.');
590 }
668 - if (__PERFORMANCE_PROFILE__) {
669 - mark('sourceConsumer.originalPositionFor()');
670 - }
591 // Now that the source map has been loaded,
592 // extract the original source for later.
673 - const {source} = sourceConsumer.originalPositionFor({
674 - line: lineNumber,
675 -
676 - // Column numbers are represented differently between tools/engines.
677 - // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based.
678 - // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991
679 - column: columnNumber - 1,
680 - });
681 - if (__PERFORMANCE_PROFILE__) {
682 - measure('sourceConsumer.originalPositionFor()');
683 - }
593 + const {source} = withSyncPerformanceMark(
594 + 'sourceConsumer.originalPositionFor()',
595 + () =>
596 + sourceConsumer.originalPositionFor({
597 + line: lineNumber,
598 +
599 + // Column numbers are represented differently between tools/engines.
600 + // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based.
601 + // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991
602 + column: columnNumber - 1,
603 + }),
604 + );
605
606 if (source == null) {
607 // TODO (named hooks) maybe fall back to the runtime source instead of throwing?
@@ -693,16 +614,10 @@ async function parseSourceAST(
614 // It can be relative if the source map specifies it that way,
615 // but we use it as a cache key across different source maps and there can be collisions.
616 originalSourceURL = (source: string);
696 - if (__PERFORMANCE_PROFILE__) {
697 - mark('sourceConsumer.sourceContentFor()');
698 - }
699 - originalSourceCode = (sourceConsumer.sourceContentFor(
700 - source,
701 - true,
702 - ): string);
703 - if (__PERFORMANCE_PROFILE__) {
704 - measure('sourceConsumer.sourceContentFor()');
705 - }
617 + originalSourceCode = withSyncPerformanceMark(
618 + 'sourceConsumer.sourceContentFor()',
619 + () => (sourceConsumer.sourceContentFor(source, true): string),
620 + );
621
622 if (__DEBUG__) {
623 console.groupCollapsed(
@@ -756,16 +671,14 @@ async function parseSourceAST(
671 originalSourceCode.indexOf('@flow') > 0 ? 'flow' : 'typescript';
672
673 // TODO (named hooks) Parsing should ideally be done off of the main thread.
759 - if (__PERFORMANCE_PROFILE__) {
760 - mark('[@babel/parser] parse(originalSourceCode)');
761 - }
762 - const originalSourceAST = parse(originalSourceCode, {
763 - sourceType: 'unambiguous',
764 - plugins: ['jsx', plugin],
765 - });
766 - if (__PERFORMANCE_PROFILE__) {
767 - measure('[@babel/parser] parse(originalSourceCode)');
768 - }
674 + const originalSourceAST = withSyncPerformanceMark(
675 + '[@babel/parser] parse(originalSourceCode)',
676 + () =>
677 + parse(originalSourceCode, {
678 + sourceType: 'unambiguous',
679 + plugins: ['jsx', plugin],
680 + }),
681 + );
682 hookSourceData.originalSourceAST = originalSourceAST;
683 if (__DEBUG__) {
684 console.log(
@@ -778,7 +691,6 @@ async function parseSourceAST(
691 });
692 }
693 });
781 - return Promise.resolve();
694 }
695
696 function flattenHooksList(
@@ -812,7 +724,7 @@ function isUnnamedBuiltInHook(hook: HooksNode) {
724
725 function updateLruCache(
726 locationKeyToHookSourceData: Map<string, HookSourceData>,
815 -): Promise<*> {
727 +): void {
728 locationKeyToHookSourceData.forEach(
729 ({metadataConsumer, sourceConsumer, runtimeSourceURL}) => {
730 // Only set once to avoid triggering eviction/cleanup code.
@@ -830,7 +742,6 @@ function updateLruCache(
742 }
743 },
744 );
833 - return Promise.resolve();
745 }
746
747 export function purgeCachedMetadata(): void {
packages/react-devtools-shared/src/PerformanceMarks.js new
+59
@@ -0,0 +1,59 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow strict-local
8 + */
9 +
10 +import {__PERFORMANCE_PROFILE__} from './constants';
11 +
12 +function mark(markName: string): void {
13 + performance.mark(markName + '-start');
14 +}
15 +
16 +function measure(markName: string): void {
17 + performance.mark(markName + '-end');
18 + performance.measure(markName, markName + '-start', markName + '-end');
19 +}
20 +
21 +export async function withAsyncPerformanceMark<TReturn>(
22 + markName: string,
23 + callback: () => Promise<TReturn>,
24 +): Promise<TReturn> {
25 + if (__PERFORMANCE_PROFILE__) {
26 + mark(markName);
27 + const result = await callback();
28 + measure(markName);
29 + return result;
30 + }
31 + return callback();
32 +}
33 +
34 +export function withSyncPerformanceMark<TReturn>(
35 + markName: string,
36 + callback: () => TReturn,
37 +): TReturn {
38 + if (__PERFORMANCE_PROFILE__) {
39 + mark(markName);
40 + const result = callback();
41 + measure(markName);
42 + return result;
43 + }
44 + return callback();
45 +}
46 +
47 +export function withCallbackPerformanceMark<TReturn>(
48 + markName: string,
49 + callback: (done: () => void) => TReturn,
50 +): TReturn {
51 + if (__PERFORMANCE_PROFILE__) {
52 + mark(markName);
53 + const done = () => {
54 + measure(markName);
55 + };
56 + return callback(done);
57 + }
58 + return callback(() => {});
59 +}