Utilizing Source Maps in DevTools

This document describes how to utilize source maps and translate raw runtime locations into original source locations inside the DevTools frontend.

DevTools provides a set of high-level abstractions and UI widgets to parse, symbolize, and render stack traces and errors. Prefer these tools over manual coordinate translation or raw string parsing.


Central Coordinate Translation: DebuggerWorkspaceBinding

The DebuggerWorkspaceBinding class (located in front_end/models/bindings/) acts as the central coordinator for mapping compiled/raw runtime coordinates to workspace/UI locations. It manages various source mappings (such as source maps, compiler mappings, and language plugins).

Translating Raw Locations

To convert a single raw debugger location (with a script ID, line number, and column number) into an original source location, use:

const uiLocation = await DebuggerWorkspaceBinding.instance()
    .rawLocationToUILocation(rawLocation);

Since source maps may need to be loaded or parsed, this method returns a Promise resolving to Workspace.UISourceCode.UILocation | null.


Structured Stack Trace Abstractions

The project organizes stack traces and errors around two primary models:

1. StackTrace

Located in front_end/models/stack_trace/, a StackTrace represents a structured stack trace. It is composed of:

  • syncFragment (Fragment): The synchronous part of the call stack.
  • asyncFragments (AsyncFragment[]): Asynchronous call stack segments, each with a description (e.g., “Promise.then”) and its own frames.

Each frame (Frame) contains properties like url, uiSourceCode, name (translated name), rawName (untranslated name), line, column, and flags indicating if the frame isInline, isWasm, or has missingDebugInfo.

Creating a StackTrace

DebuggerWorkspaceBinding provides several helpers depending on your source format:

  • From CDP Protocol Stack Trace:
    const stackTrace = await DebuggerWorkspaceBinding.instance()
        .createStackTraceFromProtocolRuntime(protocolStackTrace, target);
    
  • From Debugger Pause Event:
    const stackTrace = await DebuggerWorkspaceBinding.instance()
        .createStackTraceFromDebuggerPaused(pausedDetails, target);
    
  • From an Error-Like Stack String:
    const stackTrace = await DebuggerWorkspaceBinding.instance()
        .createStackTraceFromErrorStackLikeString(target, stackString, exceptionDetails);
    

2. SymbolizedError

Located in front_end/models/bindings/SymbolizedError.ts, SymbolizedError is a union type of SymbolizedErrorObject and UnparsableError. It represents a fully parsed and symbolized Error object.

  • SymbolizedErrorObject: Contains the parsed error message (message), the parsed ParsedErrorStackTrace (stackTrace), and an optional cause (SymbolizedError), which allows recursive representation of chained errors. It also handles special cases like compile-time or eval-time SyntaxErrors, exposing a syntaxErrorLocation pointing directly to where the parse failed.
  • UnparsableError: A fallback representation for stack traces that cannot be structurally parsed.

Creating a SymbolizedError

To resolve a RemoteObject (of subtype error or type string) into a symbolized representation:

const symbolizedError = await DebuggerWorkspaceBinding.instance()
    .createSymbolizedError(remoteObject, exceptionDetails);

Memory Management Note: Both StackTrace and SymbolizedError models listen to live location updates and must be properly dispose()d when no longer used to prevent memory leaks.


UI Widgets

To render the above models in the DevTools UI, you should use the following pre-built widgets instead of constructing your own custom tables or lists:

1. StackTracePreviewContent

Located in front_end/ui/legacy/components/utils/JSPresentationUtils.ts, this widget renders a structured StackTrace inside a shadow DOM. It automatically handles collapsible sections (expanded/collapsed) and ignore-listed files or folders.

Usage:

import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as Workspace from '../../models/workspace/workspace.js';

const preview = new Components.JSPresentationUtils.StackTracePreviewContent();
preview.stackTrace = stackTrace;
preview.options = {
  expandable: true,
  showColumnNumber: true,
  ignoreListManager: Workspace.IgnoreListManager.IgnoreListManager.instance(),
};

2. SymbolizedErrorWidget

Located in front_end/panels/console/SymbolizedErrorWidget.ts, this widget is designed to display a complete SymbolizedError, including its parsed message, any nested cause errors (rendered recursively with “Caused by:”), and links for syntax error locations.

Usage:

import * as Panels from '../../panels/panels.js';
import * as Workspace from '../../models/workspace/workspace.js';

const errorWidget = new Panels.Console.SymbolizedErrorWidget();
errorWidget.error = symbolizedError;
errorWidget.ignoreListManager = Workspace.IgnoreListManager.IgnoreListManager
    .instance();

Reaching Out

If none of the existing methods, abstractions, or widgets cover your specific use-case, or if you need additional capabilities for coordinate/stack trace symbolization, please reach out to the DevTools team. Do not roll your own coordinate mapping or raw string parsing logic.