Rich-Harris / butternut

The fast, future-friendly minifier
https://butternut.now.sh
MIT License
1.17k stars 17 forks source link

Mangling function/class declaration names is dangerous #17

Open Rich-Harris opened 7 years ago

Rich-Harris commented 7 years ago

Code might refer to fn.name. Uglify, Closure and Babili all mangle function names by default, so maybe we should too. Either way we should certainly have the option to preserve function and class names.

(In an ideal world we might be able to determine whether it's safe to mangle a given function's name — e.g. in the following snippet there is no possibility of the name mattering, and we could determine as much statically):


function foo () {
  function bar () {
    console.log('the name of this function does not matter');
  }

  bar();
}
Rich-Harris commented 7 years ago

Incidentally, disabling mangling for classes and functions is relatively easy — just need to change this function:

Object.keys( this.declarations ).forEach( name => {
  const declaration = this.declarations[ name ];

+  if ( /^(Function|Class)/.test( declaration.node.parent.type ) && declaration.node === declaration.node.parent.id ) {
+    return;
+  }

  declaration.alias = this.createIdentifier( used );

  declaration.instances.forEach( instance => {
    const replacement = instance.parent.type === 'Property' && instance.parent.shorthand ?
      `${instance.name}:${declaration.alias}` :
      declaration.alias;

    code.overwrite( instance.start, instance.end, replacement, true );
  });
});
Rich-Harris commented 7 years ago

On the flip side, when mangling is enabled, we should remove function names for all FunctionExpression nodes whose names are not referenced inside the function (which should be easy to determine)