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.
Brian Vaughn committed
Sep 24, 2021 at 11:09 UTC
b1a1cb11680cf4a03932e8955f64d5a7ba9c89f1
1 file changed
+19
-3
packages/react-devtools-shared/src/hooks/SourceMapConsumer.js
+19
-3
@@ -11,6 +11,7 @@ import {decode} from 'sourcemap-codec';
11
12
import type {
13
IndexSourceMap,
14
+ IndexSourceMapSection,
15
BasicSourceMap,
16
MixedSourceMap,
17
} from './SourceMapTypes';
@@ -34,7 +35,7 @@ export type SourceMapConsumerType = {|
35
type Mappings = Array<Array<Array<number>>>;
36
37
export default function SourceMapConsumer(
37
- sourceMapJSON: MixedSourceMap,
38
+ sourceMapJSON: MixedSourceMap | IndexSourceMapSection,
39
): SourceMapConsumerType {
40
if (sourceMapJSON.sections != null) {
41
return IndexedSourceMapConsumer(((sourceMapJSON: any): IndexSourceMap));
@@ -137,13 +138,22 @@ function BasicSourceMapConsumer(sourceMapJSON: BasicSourceMap) {
138
}: any): SourceMapConsumerType);
139
}
140
141
+type Section = {|
142
+ +generatedColumn: number,
143
+ +generatedLine: number,
144
+ +map: MixedSourceMap,
145
+
146
+ // Lazily parsed only when/as the section is needed.
147
+ sourceMapConsumer: SourceMapConsumerType | null,
148
+|};
149
+
150
function IndexedSourceMapConsumer(sourceMapJSON: IndexSourceMap) {
151
let lastOffset = {
152
line: -1,
153
column: 0,
154
};
155
146
- const sections = sourceMapJSON.sections.map(section => {
156
+ const sections: Array<Section> = sourceMapJSON.sections.map(section => {
157
const offset = section.offset;
158
const offsetLine = offset.line;
159
const offsetColumn = offset.column;
@@ -161,7 +171,8 @@ function IndexedSourceMapConsumer(sourceMapJSON: IndexSourceMap) {
171
// The offset fields are 0-based, but we use 1-based indices when encoding/decoding from VLQ.
172
generatedLine: offsetLine + 1,
173
generatedColumn: offsetColumn + 1,
164
- sourceMapConsumer: new SourceMapConsumer(section.map),
174
+ map: section.map,
175
+ sourceMapConsumer: null,
176
};
177
});
178
@@ -229,6 +240,11 @@ function IndexedSourceMapConsumer(sourceMapJSON: IndexSourceMap) {
240
);
241
}
242
243
+ if (section.sourceMapConsumer === null) {
244
+ // Lazily parse the section only when it's needed.
245
+ section.sourceMapConsumer = new SourceMapConsumer(section.map);
246
+ }
247
+
248
return section.sourceMapConsumer.originalPositionFor({
249
columnNumber,
250
lineNumber,