perf(packages/codegen): eagerly initialize mapNames (#25979)

Previously `mapNames` property of state was lazily initialized - it started as `null`, and an array is only created when a named mapping is written.

Often lazy initialization is a good strategy, but in this case IMO it's a poor trade-off - it adds a check for every named mapping that's written in return for saving a single allocation per file, and only in files which produce a source map with no names. Allocating 1 empty array is very cheap.
This commit is contained in:
overlookmotel committed 2026-08-24 08:59:56 +00:00
1 parent 5b43c60386
commit 53f62701f8
3 files changed
+9 -11

No files matched your search

+5 -7
View File
@@ -39,15 +39,13 @@ const ASCII_DECODER = /* @__PURE__ */ new TextDecoder();
*/
export function generateSourceMap(state: State, options: Options): SourceMap {
debugAssert(
state.mapPositions !== null,
"Source map positions should exist when sourcemap generation is enabled",
state.mapPositions !== null && state.mapNames !== null && state.sourceText !== null,
"`mapPositions`, `mapNames` and `sourceText` should be defined when source maps are enabled",
);
const { output, mapPositions, mapNames, sourceText } = state;
const mappingCount = mapPositions.length >> 1;
debugAssert(sourceText !== null, "`sourceText` should be defined when producing a source map");
if (mappingCount === 0) {
return {
version: 3,
@@ -65,7 +63,7 @@ export function generateSourceMap(state: State, options: Options): SourceMap {
const names: string[] = [];
let nameIds: Map<string, number> | undefined;
let mapNameEntryIndex = 0;
let nextNamedMappingIndex = (mapNames?.[0] as number | undefined) ?? Infinity;
let nextNamedMappingIndex = (mapNames[0] as number | undefined) ?? Infinity;
let sourceLineStarts: number[] | undefined;
let sourceScanOffset = 0;
@@ -244,7 +242,7 @@ export function generateSourceMap(state: State, options: Options): SourceMap {
if (index === nextNamedMappingIndex) {
nameIds ??= new Map<string, number>();
const name = mapNames![mapNameEntryIndex + 1] as string;
const name = mapNames[mapNameEntryIndex + 1] as string;
let nameId = nameIds.get(name);
if (nameId === undefined) {
nameId = names.length;
@@ -255,7 +253,7 @@ export function generateSourceMap(state: State, options: Options): SourceMap {
mappingLength = writeVlq(mappingBuffer, mappingLength, nameId - previousNameId);
previousNameId = nameId;
mapNameEntryIndex += 2;
nextNamedMappingIndex = (mapNames![mapNameEntryIndex] as number | undefined) ?? Infinity;
nextNamedMappingIndex = (mapNames[mapNameEntryIndex] as number | undefined) ?? Infinity;
}
hasSegmentOnLine = true;
+3 -3
View File
@@ -490,8 +490,8 @@ function markMapNamed(state: State, node: NamedMappableNode): void {
if (!SOURCEMAPS || !hasMappableSpan(node)) return;
debugAssert(
state.mapPositions !== null && state.sourceText !== null,
"`mapPositions` and `sourceText` should be defined when source maps are enabled",
state.mapPositions !== null && state.mapNames !== null && state.sourceText !== null,
"`mapPositions`, `mapNames` and `sourceText` should be defined when source maps are enabled",
);
const { start, end } = node;
@@ -541,7 +541,7 @@ function markMapNamed(state: State, node: NamedMappableNode): void {
// A transformed or hand-authored AST can carry ranges unrelated to `sourceText`.
// Preserve the existing fallback in that case instead of recording an arbitrary source substring.
if (originalName === undefined || !isSameToken(originalName, printedName, hashLength)) {
(state.mapNames ??= []).push(
state.mapNames.push(
mapPositions.length >> 1,
originalName === undefined ? printedName : originalName,
);
+1 -1
View File
@@ -146,7 +146,7 @@ export class State {
debugAssert(options.sourceText != null);
this.sourceText = options.sourceText;
this.mapPositions = [];
this.mapNames = null;
this.mapNames = [];
}
}
}