terser / terser

🗜 JavaScript parser, mangler and compressor toolkit for ES6+

Home Page:https://terser.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Terser breaks ability to debug

olfek opened this issue · comments

commented

I have this in my webpack config

...
optimization: {
    minimize: true,
    minimizer: [new TerserPlugin(
        {
            terserOptions: {
                sourceMap: {
                    content: 'inline',
                    includeSources: true,
                    url: 'inline'
                }
            }
        })],
},
...

Everything is undefined when stepping over code in the browser.

Switching mangle off makes the problem go away.

Why is this happening? 😕😕😕

When Terser mangles, does it not update the sourcemap with information to de-mangle?

commented

FYI - the code that the Terser plugin gets has passed through the TypeScript loader (with sourcemap included)

I think there are a few reasons for this:

  • When identifiers are mangled, browsers have to figure out what original identifiers they correspond to. Although the source map does store the original identifiers, it's just a set of unique names and doesn't account for things like reusing the same variable name across functions, shadowing etc.
  • Although browsers do have the ability to do this, it may not be enabled:
    • In Firefox, scope mapping must be enabled in the debugger image
    • In Chrome, an experiment must be enabled image
  • The scope mapping may not be entirely reliable. In particular, it may fail when the source language is not natively supported by the browser (like TypeScript).

That last point may be where things are failing for you. Once my TypeScript code got too complex, the scope mapping started failing for me.

The only workaround I've found is to first transpile from TypeScript to JavaScript without producing a source map, then use the resulting JavaScript as the source for any further transforms (like @babel/preset-env and terser). If you use @babel/preset-typescript you can pass retainLines: true so that it tries to match the line numbers of the input file.

It's possible that the situation could be improved by making terser's source maps more detailed. Right now as far as I can tell the source maps are language agnostic - they simply map a bunch of characters in the output file back to a bunch of characters in the input file. Scope mapping might work better if terser produced source maps where each identifier gets its own fragment (and maybe something similar for scopes, like matching braces).

But I think that would require fundamentally changing how terser produces source maps into a much more manual process, and it might not even help.

commented

Very interesting, I prepared a small reproducible example that I will post in an hour or so.

From what I can see in the example, Terser eliminates many symbols entirely, which I presume means a mapping cannot be created.

Yes, if identifiers are inlined or otherwise optimized out (e.g. because they are unused, or even by a browser's JIT compiler), no mapping can take place. But this is a separate problem from mangling, since unmangled symbols can be inlined too (it might even be more worthwhile to inline them since they are longer).

commented

The Rollup TypeScript plugin has a bug (does not pass inline sourcemap to Terser) that stops you from being able to view the original source in the browser.

rollup/plugins#1470
rollup/plugins#1471

So you'll have to use the Webpack bundle for step through debugging.

commented

image

thank you @ehoogeveen-medweb [Map] wasn't enabled for me 🤦🤦🤦

the undefined variables are now "defined" 👍

Hi all

This is the heart of the sourcemap output. Something that can be easily changed here is opting in more nodes:

https://github.com/terser/terser/blob/master/lib/output.js#L2365-L2418

But from what I understand from the comments, the problem here was not Terser's fault?

Sounds like in this case it was a problem with the Firefox devtools configuration, and in general I don't think it's terser's fault when scope mapping fails.

But thank you for the reference! I completely missed that list. I'll have to find some time to experiment with extending the list of AST nodes to see if it fixes my TypeScript debugging woes.

commented

Yep all good now @fabiosantoscode , thank you both for the quick responses 🙂

Cool! @ehoogeveen-medweb if you improve anything, be sure to send a PR :)