From b1a1cb11680cf4a03932e8955f64d5a7ba9c89f1 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 24 Sep 2021 11:09:42 -0400 Subject: [PATCH] DevTools: Lazily parse indexed map sections (#22415) Indexed maps divide nested source maps into sections, annotated with a line and column offset. Since these sections are JSON and can be quickly parsed, we can easily separate them without doing the heavier base64 and VLQ decoding process. This PR updates our sourcemap parsing code to defer parsing of an indexed map section until we actually need to retrieve mappings from it. --- .../src/hooks/SourceMapConsumer.js | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/react-devtools-shared/src/hooks/SourceMapConsumer.js b/packages/react-devtools-shared/src/hooks/SourceMapConsumer.js index f0503ef91a237..53c0e8c0a57a6 100644 --- a/packages/react-devtools-shared/src/hooks/SourceMapConsumer.js +++ b/packages/react-devtools-shared/src/hooks/SourceMapConsumer.js @@ -11,6 +11,7 @@ import {decode} from 'sourcemap-codec'; import type { IndexSourceMap, + IndexSourceMapSection, BasicSourceMap, MixedSourceMap, } from './SourceMapTypes'; @@ -34,7 +35,7 @@ export type SourceMapConsumerType = {| type Mappings = Array>>; export default function SourceMapConsumer( - sourceMapJSON: MixedSourceMap, + sourceMapJSON: MixedSourceMap | IndexSourceMapSection, ): SourceMapConsumerType { if (sourceMapJSON.sections != null) { return IndexedSourceMapConsumer(((sourceMapJSON: any): IndexSourceMap)); @@ -137,13 +138,22 @@ function BasicSourceMapConsumer(sourceMapJSON: BasicSourceMap) { }: any): SourceMapConsumerType); } +type Section = {| + +generatedColumn: number, + +generatedLine: number, + +map: MixedSourceMap, + + // Lazily parsed only when/as the section is needed. + sourceMapConsumer: SourceMapConsumerType | null, +|}; + function IndexedSourceMapConsumer(sourceMapJSON: IndexSourceMap) { let lastOffset = { line: -1, column: 0, }; - const sections = sourceMapJSON.sections.map(section => { + const sections: Array
= sourceMapJSON.sections.map(section => { const offset = section.offset; const offsetLine = offset.line; const offsetColumn = offset.column; @@ -161,7 +171,8 @@ function IndexedSourceMapConsumer(sourceMapJSON: IndexSourceMap) { // The offset fields are 0-based, but we use 1-based indices when encoding/decoding from VLQ. generatedLine: offsetLine + 1, generatedColumn: offsetColumn + 1, - sourceMapConsumer: new SourceMapConsumer(section.map), + map: section.map, + sourceMapConsumer: null, }; }); @@ -229,6 +240,11 @@ function IndexedSourceMapConsumer(sourceMapJSON: IndexSourceMap) { ); } + if (section.sourceMapConsumer === null) { + // Lazily parse the section only when it's needed. + section.sourceMapConsumer = new SourceMapConsumer(section.map); + } + return section.sourceMapConsumer.originalPositionFor({ columnNumber, lineNumber,