You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Minification removes class identifiers causing observable runtime change in Class.name #1973
When using @rollup/plugin-terser, named class declarations are transformed into anonymous class expressions during minification. This causes clazz.name and this.constructor.name to return an empty string ("") instead of the original class name. This results in observable runtime differences between development and production builds.
Behavior
Terser removes the class identifier and converts:
class MyClass {}
into:
class {}
This creates an anonymous class expression.
According to the ECMAScript specification:
ClassDeclaration → has a name
Anonymous ClassExpression → name === ""
Therefore:
clazz.name === ""
this.constructor.name === ""
Why This Is Problematic
This is not just cosmetic minification.
Class.name and constructor.name are frequently used for:
logging
debugging
dependency injection
metadata systems
serialization
runtime introspection
This creates:
different runtime behavior in dev vs prod
silent semantic changes
hard-to-debug production issues
Important Note
I understand that Terser does not guarantee preservation of Function.name.
However, this transformation introduces observable semantic differences between builds, not just identifier mangling.
@CharlieHelps using the reproduction link and the issue description, please do a best-effort triage of this issue and recommend a reasonable fix. If you have questions, please ask them first and provide 1-4 suggested answers in a b c d format.
Thanks for the ping — I did a best-effort triage from the reproduction and current plugin code.
What I found
I can reproduce the behavior.
In @rollup/plugin-terser, renderChunk sets defaults of module: true for ES output and toplevel: true for CJS output (packages/terser/src/module.ts).
The plugin forwards options through to Terser (worker calls minify(code, options) in packages/terser/src/worker.ts), with no extra class-name-specific transform.
In Terser, class/function name preservation is opt-in (keep_classnames / keep_fnames), so .name/constructor.name changes are expected unless preserved.
Triage conclusion
This looks like expected upstream Terser behavior surfaced by plugin defaults, rather than a plugin-specific semantic rewrite bug.
Recommended fix
Keep default behavior unchanged (changing defaults would likely be breaking and increase bundle size).
Add a README note in packages/terser/README.md that default minification can change runtime class/function names.
Document keep_classnames: true (and optionally keep_fnames: true) as the intended opt-in when runtime name introspection is required.
Add regression tests in packages/terser/test/test.js covering default behavior vs keep_classnames and module/toplevel overrides.
Activity
shellscape commentedon Mar 8, 2026
@CharlieHelps using the reproduction link and the issue description, please do a best-effort triage of this issue and recommend a reasonable fix. If you have questions, please ask them first and provide 1-4 suggested answers in
a b c dformat.charliecreates commentedon Mar 8, 2026
Thanks for the ping — I did a best-effort triage from the reproduction and current plugin code.
What I found
@rollup/plugin-terser,renderChunksets defaults ofmodule: truefor ES output andtoplevel: truefor CJS output (packages/terser/src/module.ts).minify(code, options)inpackages/terser/src/worker.ts), with no extra class-name-specific transform.keep_classnames/keep_fnames), so.name/constructor.namechanges are expected unless preserved.Triage conclusion
This looks like expected upstream Terser behavior surfaced by plugin defaults, rather than a plugin-specific semantic rewrite bug.
Recommended fix
packages/terser/README.mdthat default minification can change runtime class/function names.keep_classnames: true(and optionallykeep_fnames: true) as the intended opt-in when runtime name introspection is required.packages/terser/test/test.jscovering default behavior vskeep_classnamesandmodule/topleveloverrides.