@samitouri / QOS-React-2 / commits / abbc79d6fd

[DevTools] Only call originalPositionFor once (#22181)

Juan committed Sep 7, 2021 at 10:39 UTC abbc79d6fdaf4802951f52270b757c068cebe826
1 file changed +66 -48
packages/react-devtools-extensions/src/parseHookNames/parseSourceAndMetadata.js
+66 -48
@@ -47,6 +47,12 @@ type HookParsedMetadata = {|
47 // Original source URL if there is a source map, or the same as runtimeSourceURL.
48 originalSourceURL: string | null,
49
50 + // Line number in original source code.
51 + originalSourceLineNumber: number | null,
52 +
53 + // Column number in original source code.
54 + originalSourceColumnNumber: number | null,
55 +
56 // APIs from source-map for parsing source maps (if detected).
57 sourceConsumer: SourceConsumer | null,
58 |};
@@ -151,47 +157,18 @@ function findHookNames(
157 return null; // Should not be reachable.
158 }
159
154 - const {originalSourceURL, sourceConsumer} = hookParsedMetadata;
155 -
156 - let originalSourceColumnNumber;
157 - let originalSourceLineNumber;
158 - if (areSourceMapsAppliedToErrors() || !sourceConsumer) {
159 - // Either the current environment automatically applies source maps to errors,
160 - // or the current code had no source map to begin with.
161 - // Either way, we don't need to convert the Error stack frame locations.
162 - originalSourceColumnNumber = columnNumber;
163 - originalSourceLineNumber = lineNumber;
164 - } else {
165 - // TODO (named hooks) Refactor this read, github.com/facebook/react/pull/22181
166 - const position = withSyncPerformanceMark(
167 - 'sourceConsumer.originalPositionFor()',
168 - () =>
169 - sourceConsumer.originalPositionFor({
170 - line: lineNumber,
171 -
172 - // Column numbers are represented differently between tools/engines.
173 - // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based.
174 - // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991
175 - column: columnNumber - 1,
176 - }),
177 - );
178 -
179 - originalSourceColumnNumber = position.column;
180 - originalSourceLineNumber = position.line;
181 - }
182 -
183 - if (__DEBUG__) {
184 - console.log(
185 - `findHookNames() mapped line ${lineNumber}->${originalSourceLineNumber} and column ${columnNumber}->${originalSourceColumnNumber}`,
186 - );
187 - }
160 + const {
161 + originalSourceURL,
162 + originalSourceColumnNumber,
163 + originalSourceLineNumber,
164 + } = hookParsedMetadata;
165
166 if (
167 originalSourceLineNumber == null ||
168 originalSourceColumnNumber == null ||
169 originalSourceURL == null
170 ) {
194 - return null;
171 + return null; // Should not be reachable.
172 }
173
174 let name;
@@ -241,6 +218,8 @@ function initializeHookParsedMetadata(
218 originalSourceAST: null,
219 originalSourceCode: null,
220 originalSourceURL: null,
221 + originalSourceLineNumber: null,
222 + originalSourceColumnNumber: null,
223 sourceConsumer: null,
224 };
225
@@ -286,21 +265,45 @@ function parseSourceAST(
265 return;
266 }
267
268 + if (
269 + hookParsedMetadata.originalSourceURL != null &&
270 + hookParsedMetadata.originalSourceCode != null &&
271 + hookParsedMetadata.originalSourceColumnNumber != null &&
272 + hookParsedMetadata.originalSourceLineNumber != null
273 + ) {
274 + // Use cached metadata.
275 + return;
276 + }
277 +
278 + const {lineNumber, columnNumber} = hookSourceAndMetadata.hookSource;
279 + if (lineNumber == null || columnNumber == null) {
280 + throw Error('Hook source code location not found.');
281 + }
282 +
283 const {metadataConsumer, sourceConsumer} = hookParsedMetadata;
284 const runtimeSourceCode = ((hookSourceAndMetadata.runtimeSourceCode: any): string);
285 let hasHookMap = false;
286 let originalSourceURL;
287 let originalSourceCode;
294 - if (sourceConsumer !== null) {
288 + let originalSourceColumnNumber;
289 + let originalSourceLineNumber;
290 + if (areSourceMapsAppliedToErrors() || sourceConsumer == null) {
291 + // Either the current environment automatically applies source maps to errors,
292 + // or the current code had no source map to begin with.
293 + // Either way, we don't need to convert the Error stack frame locations.
294 + originalSourceColumnNumber = columnNumber;
295 + originalSourceLineNumber = lineNumber;
296 + // There's no source map to parse here so we can just parse the original source itself.
297 + originalSourceCode = runtimeSourceCode;
298 + // TODO (named hooks) This mixes runtimeSourceURLs with source mapped URLs in the same cache key space.
299 + // Namespace them?
300 + originalSourceURL = hookSourceAndMetadata.runtimeSourceURL;
301 + } else {
302 // Parse and extract the AST from the source map.
296 - const {lineNumber, columnNumber} = hookSourceAndMetadata.hookSource;
297 - if (lineNumber == null || columnNumber == null) {
298 - throw Error('Hook source code location not found.');
299 - }
303 // Now that the source map has been loaded,
304 // extract the original source for later.
305 // TODO (named hooks) Refactor this read, github.com/facebook/react/pull/22181
303 - const {source} = withSyncPerformanceMark(
306 + const {column, line, source} = withSyncPerformanceMark(
307 'sourceConsumer.originalPositionFor()',
308 () =>
309 sourceConsumer.originalPositionFor({
@@ -320,6 +323,8 @@ function parseSourceAST(
323 );
324 }
325
326 + originalSourceColumnNumber = column;
327 + originalSourceLineNumber = line;
328 // TODO (named hooks) maybe canonicalize this URL somehow?
329 // It can be relative if the source map specifies it that way,
330 // but we use it as a cache key across different source maps and there can be collisions.
@@ -331,7 +336,7 @@ function parseSourceAST(
336
337 if (__DEBUG__) {
338 console.groupCollapsed(
334 - 'parseSourceAST() Extracted source code from source map',
339 + `parseSourceAST() Extracted source code from source map for "${originalSourceURL}"`,
340 );
341 console.log(originalSourceCode);
342 console.groupEnd();
@@ -343,24 +348,37 @@ function parseSourceAST(
348 ) {
349 hasHookMap = true;
350 }
346 - } else {
347 - // There's no source map to parse here so we can just parse the original source itself.
348 - originalSourceCode = runtimeSourceCode;
349 - // TODO (named hooks) This mixes runtimeSourceURLs with source mapped URLs in the same cache key space.
350 - // Namespace them?
351 - originalSourceURL = hookSourceAndMetadata.runtimeSourceURL;
351 + }
352 +
353 + if (__DEBUG__) {
354 + console.log(
355 + `parseSourceAST() mapped line ${lineNumber}->${originalSourceLineNumber} and column ${columnNumber}->${originalSourceColumnNumber}`,
356 + );
357 }
358
359 hookParsedMetadata.originalSourceCode = originalSourceCode;
360 hookParsedMetadata.originalSourceURL = originalSourceURL;
361 + hookParsedMetadata.originalSourceLineNumber = originalSourceLineNumber;
362 + hookParsedMetadata.originalSourceColumnNumber = originalSourceColumnNumber;
363
364 if (hasHookMap) {
365 + if (__DEBUG__) {
366 + console.log(
367 + `parseSourceAST() Found hookMap and skipping parsing for "${originalSourceURL}"`,
368 + );
369 + }
370 // If there's a hook map present from an extended sourcemap then
371 // we don't need to parse the source files and instead can use the
372 // hook map to extract hook names.
373 return;
374 }
375
376 + if (__DEBUG__) {
377 + console.log(
378 + `parseSourceAST() Did not find hook map for "${originalSourceURL}"`,
379 + );
380 + }
381 +
382 // The cache also serves to deduplicate parsing by URL in our loop over location keys.
383 // This may need to change if we switch to async parsing.
384 const sourceMetadata = originalURLToMetadataCache.get(originalSourceURL);