sleeuwen/sourcemaps

Incorrect source map parsing?

magnusottosson opened this issue · 3 comments

Hi,

I'm trying to trace a stacktrace for a script that has been created by webpack. The stacktrace comes from server side rendering this using ReactJS.NET and "V8JsEngine".

The original stacktrace looks like

at useFilterQs (hbd-ssr.1d6f13df.js:283:9)
    at ProductList (hbd-ssr.1d6f13df.js:4774:79)
    at processChild (hbd-ssr.1d6f13df.js:56618:14)
    at resolve (hbd-ssr.1d6f13df.js:56535:5)
    at render (hbd-ssr.1d6f13df.js:57010:22)
    at read (hbd-ssr.1d6f13df.js:56948:29)
    at renderToString (hbd-ssr.1d6f13df.js:57563:27)
    at Script [3]:1:16

Using this library I get:

test at Error (webpack:///../src/UI/hbd-ui/src/base/hooks/use-filter-qs.ts:14:11)
 at webpack:///../src/UI/hbd-ui/src/components/products/list/index.tsx:79:25
 at webpack:///../node_modules/react-dom/cjs/react-dom-server.browser.development.js:3042:1
 at webpack:///../node_modules/react-dom/cjs/react-dom-server.browser.development.js:2959:1
 at webpack:///../node_modules/react-dom/cjs/react-dom-server.browser.development.js:3434:1
 at webpack:///../node_modules/react-dom/cjs/react-dom-server.browser.development.js:3372:1
 at webpack:///../node_modules/react-dom/cjs/react-dom-server.browser.development.js:3987:1
 at Script ([3]:1:16)

If I instead of rendering this on the server let the client render I get the following stacktrace:

Uncaught Error: test
    at useFilterQs (use-filter-qs.ts:14)
    at ProductList (index.tsx:79)
    at renderWithHooks (react-dom.development.js:14803)
    at mountIndeterminateComponent (react-dom.development.js:17482)
    at beginWork (react-dom.development.js:18596)
    at HTMLUnknownElement.callCallback (react-dom.development.js:188)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
    at invokeGuardedCallback (react-dom.development.js:292)
    at beginWork$1 (react-dom.development.js:23203)
    at performUnitOfWork (react-dom.development.js:22154)

It seems like I'm loosing the function names? I tried validating this using tools like stacktracify (https://github.com/mifi/stacktracify). This tools gives me the same result as you library. This lead me to that maybe its a webpack problem. But it seems like the browser is able to parse the source map correclty. Is is it just doing something else to make it work?

I can see that the Frame has the correct method names but it get overriden by the OriginalName property from the SourceMapMappingEntry. Is this correct?

{SourceMaps.SourceMapMappingEntry}
    GeneratedColumnNumber: 74
    GeneratedLineNumber: 88920
    OriginalColumnNumber: 31
    OriginalFileName: "webpack:///../src/UI/hbd-ui/src/base/hooks/use-filter-qs.ts"
    OriginalLineNumber: 13
    OriginalName: "location"

{SourceMaps.SourceMapMappingEntry}
    GeneratedColumnNumber: 85
    GeneratedLineNumber: 93715
    OriginalColumnNumber: 24
    OriginalFileName: "webpack:///../src/UI/hbd-ui/src/components/products/list/index.tsx"
    OriginalLineNumber: 78
    OriginalName: null
frame.File = originalPosition?.OriginalFileName;
frame.Method = originalPosition?.OriginalName;
frame.LineNumber = originalPosition?.OriginalLineNumber + 1;
frame.ColumnNumber = originalPosition?.OriginalColumnNumber + 1;

Hi Magnus,

Thanks for checking out this library, I haven't specifically used it for SSR purposes myself but it sounds like a great use case.

If I understand it correctly, the original stacktrace is actually only missing filename and line/column number information and not the variable names, that would suggest we could default to the frame.Method if entry.OriginalName is null (but might have other implications).

But if that assumption is correct, the first SourceMapMappingEntry you added actually does have a OriginalName ("location"), which I can't see anywhere in the browser stracktrace, do you know where that comes from and if that's relevant in this example?

As for the fact the browser can parse the stacktrace correctly, I believe you should have 2 different source maps as there are 2 different files created, one for SSR and one for the browser. So it might be a problem only with the SSR source map. (can you confirm this and also that you're not possibly using the browser source map on the SSR stacktrace?)

I would like to try this out myself, do you know of any easy sample project with all this ready to go or an easy guide to set it up?

Thanks for the reply!

If I understand it correctly, the original stacktrace is actually only missing filename and line/column number information and not the variable names, that would suggest we could default to the frame.Method if entry.OriginalName is null (but might have other implications).

Yes, thats correct. And yes we could use frame.Method when entry.OriginalName. Fram.Method will not work if the method names are minimized. Then they will be like a,b,c...

But if that assumption is correct, the first SourceMapMappingEntry you added actually does have a OriginalName ("location"), which I can't see anywhere in the browser stracktrace, do you know where that comes from and if that's relevant in this example?

Yes, this is actually a misstake from my side. The location comes from another stackltrace. Then it was a variable called location that was null. So it was still not the method name It was the variable name that was null. A bit weird.

As for the fact the browser can parse the stacktrace correctly, I believe you should have 2 different source maps as there are 2 different files created, one for SSR and one for the browser. So it might be a problem only with the SSR source map. (can you confirm this and also that you're not possibly using the browser source map on the SSR stacktrace?)

I have two scritps, one for ssr and one for client. I could use the same builds but there is one library that has references to window and that will make the SSR thing crash. So we are building two builds. One of client and one for SSR. I'm using the right map though and they are different webpack builds.

I would like to try this out myself, do you know of any easy sample project with all this ready to go or an easy guide to set it up?

The project I have at hand is huge and complex :) I will try and see if I can create some sample project.

Hi Magnus,

I've had a look at this issue and set up a very simple application using the ReactJS.NET library (though not using different files for client and server rendering). I believe based on my results that the stacktrace returned by the library is correct for the generated source map.

The way we recreate the stacktrace is by parsing the file, line and column numbers and mapping that with the help of the source map to the original location (and name). If we look at the first line in your stack trace, notice that the corresponding name is the function name in which it is executing. This is different from the source map, which will return the name of the variable at which the error occurred (that's why the name in your first SourceMapMappingEntry was "location", as the error occurred on that variable). Also, if you look at the stacktrace for the react-dom-server files the columns for all of the stack frames are 1, which means there probably wasn't any column information embedded in the source map for that location, the actual name of the method that was called is on a different column which is why we don't get the correct function names for those frames (I'm actually not sure why the column information would be missing though, I would have to look at it further).

I tried recreating the stacktrace with some other node libraries, but I got the same results as with this library. I did find the stacktrace-gps library which did manage to get the function name, but looking at the source code they managed to do this by looking at the source code and inspecting some lines above where the exception happened. We might be able to do something similar when the sourcemap contains the sourcesContent, but it's still not a perfect solution. Based on the fact the other libraries give the same result I don't think we should change it to use a half-baked solution. If you feel differently about this of have other ideas on how to improve it let me know. Otherwise, I will keep an eye open for possible ways to improve it but won't change anything for now.