Skip to content

Proposal: Source Maps v4 (or v3.1): Improved post-hoc debuggability #12

Closed
@robpaveza

Description

@robpaveza

Hello! At a recent TC-39 JS Tools meeting we decided to bring the proposal for v4 here as a neutral discussion point.

The proposal document is here: MicrosoftEdge/MSEdgeExplainers#538

(I'd be happy to stage a Pull Request against this or another repo where appropriate. We discussed whether to update the Google Doc which is the "official" standard, but given it's been 8-9 years since that document was last updated, I'm not sure what the best way is to formalize and/or collaborate on that document, vs. treating it as an "artifact").

TL;DR

The proposal is to add (one or two) new field(s) to the existing Source Maps document. This would map text ranges of the source files to a "scope", which would describe the lexical subroutine from the source language. For example:

1  class Example {
2    constructor() {
3      document.addEventListener('ready', () => {
4      });
5    }
6  }

This would produce the following list of scopes:

  • 2:2 ... 5:2 named constructor for class Example
  • 3:46 ... 4:4 names anonymous callback for document.addEventListener

(Please note: the names of these scopes is up for discussion).

This would enable a series of improvements wherever tooling exposes minified code artifacts related to the call stack:

  • Call stack window
  • Output call stacks (Error.stack)
  • Performance traces
  • Memory snapshots
  • Exported HARs

Primary Points of Discussion

While the discussion group believes that solving these problems is valuable, there have been the following major points of discussion:

Storing function names

Option 1: Store in the existing “names” field
Option 2: Introduce a new “scopeNames” field

The main benefit of Option 1 is that it reduces sourcemap size and avoids duplication. This is because many tools already populate the “names” field with many of the function names and they can be directly referenced in the “scopes” field.
The main downside is that if any tool modifies the “names” field by removing an element or changing the order, they will need to become “scopes”-aware and update it accordingly.

Recommendation: Option 1 is preferred unless there is evidence that the “names” field is tampered with by tools in practice.

Keying “scopes” by generated index VS source index

Option 1: Key in “scopes” is source line and column
Option 2: Key in “scopes” is generated line and column

The main benefit of Option 1 is that only the first tool in a pipeline, and any tool that combines sources, needs to support the new “scopes” field. Other tools can ignore it. Note that the use case for decoding a function name will always involve decoding back to the original source location anyway, so this option does not add extra complexity.
Option 2 has a benefit of using the same approach as the existing “mappings” field so can feel more consistent.

Recommendation: Option 1 is preferred

Nested scopes VS linear scopes

Option 1: Scopes are nested
Option 2: Scopes are linear

Option 1 has the benefit of representing the logical structure of the code, as well as requiring only one VLQ per function. With Option 2, a function with many inner functions will need to be repeatedly referenced every time an inner function ends.

Recommendation: Option 1 is preferred

Format of “scopes” field

Option 1: Starting points
Option 2: Ranges

Option 1 has the benefit of being consistent with the existing “mappings” field and tools can reuse implementation. It also has the benefit of resulting in smaller sourcemaps due to only specifying starting locations and a scope name index.
Option 2 results in larger sourcemaps. However, it has the benefit of representing the logical structure of the code better with a 1-1 mapping between a function and its VLQ.

Recommendation: Option 2 is preferred

Relative VS absolute indices

This will very much depend on the format chosen in the decision point above.

Versioning

Option 1: Version 4
Option 2: Version 3.1
Option 3: Retain version 3, but just add new fields

Option 1 has the benefit of indicating a major version update. Option 2 has the benefit of indicating a minor version update but that the update is non-breaking (conforming to semver). Option 3 has the benefit of being very JavaScripty, in that new fields can just be detected and light up, but might break strict compliance testers.

Recommendation: Option 1 or 2 is preferred; Option 3 is likely to break one or more validators.

Naming of functions

This decision point relates to the naming convention of functions. While a free function f() will of course be named f, there are more choices available for other types of functions. For example, does a class member function get Class.prototype.f or Class.f as its name, or how do you name an anonymous function? These decisions probably don’t belong in the spec, but it would be useful to have a common naming convention across tools.

Other things that might be nice to solve in the future

This section was added by an edit

[ ] Information about functions that were inlined during compilation (surfaced by @ldarbi below)
[ ] Direct information about aliasing of variables (this was mentioned by @rbuckton during the call and @sokra below)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions