-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend Source Maps to support post-hoc debugging #46695
Comments
Hey Rob, thanks for the proposal here. My thoughts here are that it would be worthwhile to try to get this into the sourcemap spec first; using a branch of TypeScript as a proof of concept implementation might be useful to prove out the proposal for the spec. I'll point out though that I don't think we even support the |
Isn't ...yeah, I was right, |
@DanielRosenwasser, I think you meant Several years ago, @andysterland and I did an investigation into other extensions to the source map spec, primarily around identifying scopes and aliased names inside of a scope. Unfortunately, nothing ever came of that endeavor as the solution we were investigating wasn't sufficient for tools like minifiers. |
I'm not sure what you and Andy discussed back then, but I was discussing with some folks here on DevTools and our tentative belief is that so long as TypeScript emitted a new entry in the VLQ, I believe that entry could simply be preserved ('ish' -- it might need to be offset if a downstream tool inserted new entries into the function foo(bar: number): never {
throw new Error('Intentional.');
}
foo(); This would likely emit: function foo(bar) {
throw new Error('Intentional.');
}
foo(); TypeScript might first emit 2 entries into
Assuming a minifier like terser or uglify came later, my supposition is that, as long as they respected the original contents of the
The source map spec outlines as many as 6 data that are contained when parsing the
Yeah, that was my thinking as well, and specifically that "it works in this TypeScript branch" might be a compelling reason to revise the spec. :) |
Hello friends, this is a valuable topic. I'm pleased to see interest in progressing the sourcemap spec. We're currently using the The extension solves the exact use-case outlined above. It permits accurate decoding of function names without guessing and without the need to consult the original source files. The sourcemap tells you everything.
We had early discussions with @bcoe about getting pasta support into Node but never got around to acting on it. Since then, Node gained a best-effort (guessing) implementation, but would still benefit from something like this to increase reliability. Please take a look at the approach for inspiration. It would be interesting to compare extending the So thank you @robpaveza for raising this issue! I'd love to see this problem more widely solved. Beyond stack trace decoding, this information could also be used in DevTools, e.g. the VSCode debugger's call stack could use it to show the original function name when debugging minified code. |
I would be interested in being looped in to this work, if an effort is made to dust off the Source Map spec. I would love to make sure Istanbul and Node.js both support extensions. |
@robpalme - I've been mulling over the options here, and I think that the most interesting possibility here is to leverage what you've put together with pasta-sourcemaps. To that end, I've authored an explainer here - see the direct explainer link - which borrows inspiration from file.ts -> file.js -> file.min.js The minifier doesn't need to know anything about these fields, it just needs to pass them through. For tools like Rollup or Webpack, it's also fairly trivial: if they have access to the original source files anyway, the originally-transpiled values can just move into the Please feel welcome to leave comments in the explainer. Unfortunately, since it's been 8 years since the previous Source Maps specification, the Mozilla list is gone (not even archived). I've asked a few colleagues if they have contacts who worked on it previously, and I'll also be offering this proposal up to the Chromium DevTools list for discussion. I think it'd be great if we can leverage any of your team's learnings from having worked with pasta-sourcemaps. |
Thanks @robpaveza - sounds good - I'll do a detailed review on the explainer PR next week. |
Hey, apologies for the slow turnaround on this. @ldarbi (original author of pasta-sourcemaps ) would like to contribute. So I'll hand the review over to her. |
class Test {
constructor() {
}
testMethod() {
}
get foo() {
return 5;
}
public x = () => { console.log('x'); };
static bar(): void {
}
}
export function configureExample() {
if (!('flatten' in Array.prototype)) {
// @ts-ignore
Array.prototype.flatten = () => {
throw new Error('Not implemented.');
};
}
} The source map which is generated by this looks like so: {
"version": 4,
"file": "example.js",
"sourceRoot": "",
"sources": [
"../src/example.ts"
],
"names": [],
"mappings": "AAAA,MAAM,IAAI;IACR;QAYO,MAAC,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAVvC,CAAC;IAED,UAAU;IAEV,CAAC;IAED,IAAI,GAAG;QACL,OAAO,CAAC,CAAC;IACX,CAAC;IAID,MAAM,CAAC,GAAG;IAEV,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE;QACnC,aAAa;QACb,KAAK,CAAC,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;YAC7B,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtC,CAAC,CAAC;KACH;AACH,CAAC",
"sourcesContent": [
"class Test {\r\n constructor() {\r\n\r\n }\r\n\r\n testMethod() {\r\n\r\n }\r\n\r\n get foo() {\r\n return 5;\r\n }\r\n\r\n public x = () => { console.log('x'); };\r\n\r\n static bar(): void {\r\n\r\n }\r\n}\r\n\r\nexport function configureExample() {\r\n if (!('flatten' in Array.prototype)) {\r\n // @ts-ignore\r\n Array.prototype.flatten = () => {\r\n throw new Error('Not implemented.');\r\n };\r\n }\r\n}\r\n"
],
"scopeNames": [
"Test.x",
"constructor for Test",
"Test.testMethod",
"Test.get foo",
"static Test.bar",
"Array.prototype.flatten",
"configureExample",
"Global code"
],
"scopes": "AakBAwCA,AZeEGC,AIcEGC,AIWEGC,AMoBEGC,AQmCEKC,AHkCOCC,ApBA4BAC"
} The [0,13,18,0,40,0], [0,-12,15,2,3,1], [0,4,14,2,3,1], [0,4,11,2,3,1], [0,6,20,2,3,1], [0,8,35,2,5,1], [0,-3,34,7,1,1], [0,-20,0,28,0,1] It would decode as follows:
So if we had an exception in which the original source location was decoded to be at
We would then analyze these and find that the nearest scope that encloses the area in question is Item 6, and that is the correct one. Without doing this in two passes, we can probably say "largest start line:col in which end line:col is after the location being searched" and do this in a single pass. |
Adding @concavelenz here, who might have an opinion and relevant insights. |
Suggestion
π Search Terms
Source maps, post hoc debugging
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
I would like to propose that TypeScript create an experimental source map extension (version 4). The purpose of this would be to improve the ability to apply Source Map data to stack traces and to have the Source Map contain everything needed to go from a minified stack trace to an unminified stack trace without using function name guessing.
π Motivating Example
Suppose I receive the following information from my application:
The source map will resolve the first stack frame to
draw(src, sprite, x, y, frame)
, and will correctly point out that the failure here is that the undefined value is actuallyframe
. However, that is not the name of the function. The function's name isdraw
, which is a member of theRender
class.If I simply apply the value of the
names
array to the function, decoding the stack trace is not particularly useful. It would look something like this:Using the source map to navigate the source code by hand, I can reconstruct the original call stack:
But doing this required that I dump the mappings and the source files from the source map and manually inspect the source files. In general, this requires that I use a library to parse the
mappings
field from Source Maps (because as of Source Maps v3, this field is stored in a stateful way).π» Use Cases
I want to use this to improve in-production debugging experiences, specifically, to improve stack traces, particularly those that exist after minification.
Presently, to work around this, we need to do one of two things:
Proposed changes to the Source Map spec
Substantively: Only the
mappings
field would be altered, and would be altered by adding the 6th field. The complete section is included below:In addition, the
version
field of the spec should be bumped to 4.Suggested names
function foo() { ... }
,const foo = () => { ... }
, { foo: function() { ... }`[anonymous function]
or[anonymous arrow function]
[anonymous function passed to addEventListener]
Global code
The text was updated successfully, but these errors were encountered: