CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-metro-symbolicate

A tool to find the source location from JS bundles and stack traces.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

chrome-devtools.mddocs/

Chrome DevTools Integration

Support for symbolicating Chrome DevTools formats including CPU profiles and heap snapshots.

Capabilities

ChromeHeapSnapshotProcessor Class

Processes and symbolicates Chrome DevTools heap snapshots and heap timelines to translate bundled locations back to original source positions.

/**
 * Processes Chrome heap snapshots for symbolication
 * @param snapshot - Chrome heap snapshot data structure
 */
class ChromeHeapSnapshotProcessor {
  constructor(snapshot: ChromeHeapSnapshot);
  
  /**
   * Symbolicates a specific location in the heap snapshot
   * @param locationIdx - Index of location in snapshot.locations array
   * @param context - Symbolication context for position translation
   */
  symbolicateLocation(locationIdx: number, context: SymbolicationContext): void;
  
  /**
   * Symbolicates all locations in the heap snapshot
   * @param context - Symbolication context for position translations
   */
  expandLocations(context: SymbolicationContext): void;
}

Usage Examples:

const { ChromeHeapSnapshotProcessor } = require('metro-symbolicate/private/ChromeHeapSnapshot');
const Symbolication = require('metro-symbolicate/private/Symbolication');
const { SourceMapConsumer } = require('source-map');
const fs = require('fs');

// Load heap snapshot and source map
const snapshotData = JSON.parse(fs.readFileSync('heap.heapsnapshot', 'utf8'));
const sourceMapContent = fs.readFileSync('bundle.js.map', 'utf8');

// Create processor and symbolication context
const processor = new ChromeHeapSnapshotProcessor(snapshotData);
const context = Symbolication.createContext(SourceMapConsumer, sourceMapContent);

// Symbolicate all locations in the snapshot
processor.expandLocations(context);

// Save symbolicated snapshot
fs.writeFileSync('symbolicated-heap.json', JSON.stringify(snapshotData));

Heap Snapshot Structure Processing

Handles the complex Chrome heap snapshot format with its various data structures and indices.

Heap Snapshot Components:

type ChromeHeapSnapshot = {
  snapshot: {
    meta: {
      trace_function_info_fields: Array<string>;
      location_fields: Array<string>;
      edge_fields: Array<string>;
      edge_types: Array<string | Array<string>>;
      node_fields: Array<string>;
      node_types: Array<string | Array<string>>;
      trace_node_fields: Array<string>;
    };
  };
  trace_function_infos: Array<number>;
  locations: Array<number>;
  edges: Array<number>;
  nodes: Array<number>;
  strings: Array<string>;
  trace_tree: RawBuffer;
};

type RawBuffer = Array<number | RawBuffer>;

Processing Example:

// Accessing heap snapshot data
const processor = new ChromeHeapSnapshotProcessor(snapshot);

// The processor provides internal utilities for working with:
// - String table lookups
// - Record field access
// - Location data manipulation
// - Trace tree navigation

// Symbolicate specific locations
const locationCount = snapshot.locations.length / snapshot.snapshot.meta.location_fields.length;
for (let i = 0; i < locationCount; i++) {
  processor.symbolicateLocation(i, context);
}

CPU Profile Symbolication

Integrates with the core symbolication API to process Chrome DevTools CPU profiles.

// CPU profile symbolication is handled through the core API
const context = Symbolication.createContext(SourceMapConsumer, sourceMapContent);

// Process CPU profile file directly
context.symbolicateChromeTrace('./profile.cpuprofile', {
  stdout: process.stdout,
  stderr: process.stderr
});

CPU Profile Structure:

CPU profiles contain stack frame information that gets symbolicated:

type ChromeTrace = {
  stackFrames: { [string]: ChromeTraceEntry };
};

type ChromeTraceEntry = {
  column: number;
  funcColumn: number;
  funcLine: number;
  funcVirtAddr: number;
  line: number;
  name: string;
  offset: number;
};

String Table Management

Efficiently manages the Chrome heap snapshot string table for lookups and modifications.

Internal String Table Operations:

// String table operations are handled internally by ChromeHeapSnapshotProcessor
// The processor provides utilities for:
// - String lookups by index
// - String additions and modifications
// - String table consistency maintenance

// Example: the processor automatically handles string table updates
// when symbolication replaces bundled paths with original source paths

Record Access Utilities

Provides structured access to Chrome heap snapshot records with their various field types.

Record Field Processing:

// The processor handles different field types:
// - String fields (indices into string table)
// - Numeric fields (direct values)
// - Enum fields (indices into type arrays)

// Field access is abstracted through internal utilities:
// - ChromeHeapSnapshotRecordAccessor: Field-based record access
// - ChromeHeapSnapshotRecordIterator: Iteration over record collections

Location Symbolication

Translates bundled JavaScript locations in heap snapshots to original source positions.

Location Processing:

const processor = new ChromeHeapSnapshotProcessor(snapshot);
const context = Symbolication.createContext(SourceMapConsumer, sourceMapContent);

// Symbolicate individual location
processor.symbolicateLocation(locationIndex, context);

// The location data gets updated in-place:
// Before: { script_id: 123, line: 1, column: 234 }
// After:  { script_id: 123, line: 15, column: 8, source: 'src/component.js' }

// Symbolicate all locations at once
processor.expandLocations(context);

Error Handling

Gracefully handles malformed heap snapshots and symbolication failures.

const { ChromeHeapSnapshotProcessor } = require('metro-symbolicate/private/ChromeHeapSnapshot');

try {
  const processor = new ChromeHeapSnapshotProcessor(snapshot);
  processor.expandLocations(context);
} catch (error) {
  if (error.message.includes('Invalid heap snapshot format')) {
    console.error('Heap snapshot data is malformed');
  } else if (error.message.includes('Missing source map data')) {
    console.error('Cannot symbolicate without valid source map');
  } else {
    console.error('Symbolication failed:', error);
  }
}

// The processor validates heap snapshot structure
// and handles missing or invalid fields gracefully

Memory Efficiency

Processes large heap snapshots efficiently with in-place modifications and streaming access patterns.

Performance Considerations:

// Large heap snapshots are processed efficiently:
// - In-place modification of location data
// - Lazy string table operations
// - Minimal memory overhead during processing

const processor = new ChromeHeapSnapshotProcessor(largeSnapshot);

// Process locations incrementally if needed
const locationFieldCount = largeSnapshot.snapshot.meta.location_fields.length;
const totalLocations = largeSnapshot.locations.length / locationFieldCount;

for (let i = 0; i < totalLocations; i++) {
  processor.symbolicateLocation(i, context);
  
  // Optional: process in batches to manage memory
  if (i % 1000 === 0) {
    console.log(`Processed ${i}/${totalLocations} locations`);
  }
}

Integration Examples

Complete examples showing integration with various Chrome DevTools workflows.

Heap Timeline Processing:

const processHeapTimeline = (timelineFile, sourceMapFile) => {
  const timelineData = JSON.parse(fs.readFileSync(timelineFile, 'utf8'));
  const sourceMapContent = fs.readFileSync(sourceMapFile, 'utf8');
  
  // Create processor and context
  const processor = new ChromeHeapSnapshotProcessor(timelineData);
  const context = Symbolication.createContext(SourceMapConsumer, sourceMapContent);
  
  // Symbolicate all locations
  processor.expandLocations(context);
  
  return timelineData;
};

// Usage
const symbolicatedTimeline = processHeapTimeline(
  'allocation-timeline.heaptimeline',
  'bundle.js.map'
);

Memory Profiling Workflow:

const analyzeMemoryProfile = (profilePath, sourceMapPath) => {
  // Load and symbolicate heap snapshot
  const snapshot = JSON.parse(fs.readFileSync(profilePath, 'utf8'));
  const sourceMap = fs.readFileSync(sourceMapPath, 'utf8');
  
  const processor = new ChromeHeapSnapshotProcessor(snapshot);
  const context = Symbolication.createContext(SourceMapConsumer, sourceMap);
  
  // Symbolicate locations
  processor.expandLocations(context);
  
  // Now analyze with original source locations
  // Extract allocation stacks, object references, etc.
  return {
    totalObjects: snapshot.nodes.length,
    symbolicatedLocations: snapshot.locations.length,
    snapshot: snapshot
  };
};

Types

type ChromeHeapSnapshotFieldType =
  | 'pointer'
  | 'array'
  | 'synthetic'
  | 'numeric'
  | 'string'
  | 'object'
  | 'code'
  | 'closure'
  | 'regexp'
  | 'number'
  | 'native'
  | 'symbol'
  | 'bigint';

type DenormalizedRecordInput = $ReadOnly<{
  [fieldName: string]: string | number;
}>;

docs

chrome-devtools.md

cli-interface.md

core-symbolication.md

ignore-list.md

index.md

source-metadata.md

tile.json