alangpierce / sucrase

Super-fast alternative to Babel for when you can target modern JS runtimes
https://sucrase.io
MIT License
5.67k stars 143 forks source link

Cannot debug with Chrome DevTools #583

Open DanielSWolf opened 3 years ago

DanielSWolf commented 3 years ago

When trying to debug Node.js code run with Sucrase, the Chrome DevTools can't find the source code because they look in the wrong path.

I'm on Windows 10 with Node 14.12.0 and Sucrase 3.17.0.

To reproduce:

  1. Create a new, empty package by running yarn init.
  2. Add sucrase as the only dependency.
  3. Add an index.ts file with the sole line console.log('test' as string);.
  4. To verify that everything works, run node --require sucrase/register index.ts. As expected, this will transpile the code and print "test".
  5. Now run node --inspect-brk --require sucrase/register index.ts to run with debugging enabled.
  6. In Chrome, go to chrome://inspect. Wait until the target index.ts appears, then click the "inspect" link next to it.
  7. The DevTools open, but the "Sources" tab shows the error message "Could not load content for file:///C:/dev/sucrase-test/C:\dev\sucrase-test\index.ts (System error: net::ERR_FILE_NOT_FOUND)".

image

It looks like DevTools look in the wrong path by concatenating the absolute path of the package with the absolute Windows path of the source file.

I believe this to be a problem with Sucrase. If I rename index.ts to index.js, remove the superfluous type assertion (to make it valid JavaScript) and run node --inspect-brk index.js (without --require sucrase/register), everything works fine.

alangpierce commented 3 years ago

Thanks for the report! Things all work on my end on macOS (though I had to open the file explicitly using Cmd/Ctrl+O), so I think this is a Windows-specific issue. I don't have a Windows VM handy, so it's hard for me to test, but Sucrase is putting file paths in the source maps, so it's possible something is going wrong in that process (though Sucrase doesn't modify paths directly).

Sucrase's register.ts file uses the pirates library to register a require hook, which passes a filePath to the callback. That then gets passed as both compiledFilename and filePath in computeSourceMap.ts. It's possible that pirates is giving a bad path here, or that Chrome expects the source map in a different format.

Have you tried using ndb instead? I think that's the newer equivalent of chrome://inspect, and might handle paths better.

Another way to troubleshoot this is you could hack the sucrase code to add a print statement to get the path received from pirates and the full JSON source map. You could edit node_modules/sucrase/dist/register.js and add this line:

console.log(`filePath: ${filePath}, sourceMap: ${JSON.stringify(sourceMap)}`);

before the declaration const mapBase64 = ....

I get this output:

filePath: /Users/alanpierce/code/sucrase-debug-test/index.ts, sourceMap: {"version":3,"file":"/Users/alanpierce/code/sucrase-debug-test/index.ts","sources":["/Users/alanpierce/code/sucrase-debug-test/index.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA","names":[]}

This would help track down if the strange path file:///C:/dev/sucrase-test/C:\dev\sucrase-test\index.ts is coming from Pirates or from Sucrase or if Chrome is coming up with it.

DanielSWolf commented 3 years ago

I tried out ndb, but it seems to be having trouble with the source maps, too. It displays the transpiled JavaScript code and shows an info that a source map has been detected, but doesn't seem to be able to load the TypeScript files.

So I hacked register.js the way you asked. This is the output:

filePath: C:\dev\sucrase-test\index.ts, sourceMap: {"version":3,"file":"C:\\dev\\sucrase-test\\index.ts","sources":["C:\
\dev\\sucrase-test\\index.ts"],"mappings":"AAAA;AACA","names":[]}

My guess is that Chrome doesn't expect absolute Windows paths. On a hunch, I added sourceMap.sources = ['file:///C:/dev/sucrase-test/index.ts']; before the const mapBase64 = ... assignment, effectively turning the Windows-style path into a URL. After that, Chrome still couldn't load the original TypeScript file, but at least it showed the transpiled contents instead of an empty window. So my guess is that tweaking these paths might lead to success. But I'm afraid I know too little about source maps.