closure-compiler icon indicating copy to clipboard operation
closure-compiler copied to clipboard

ADVANCED compilation incorrectly dead-code eliminates entire classes in modules (v20240317)

Open AshleyScirra opened this issue 1 week ago • 2 comments

Using v20240317 with the following files (attached here: repro.zip)

// namespace.js
globalThis.MyNamespace = {};
// class.js
const MyNamespace = globalThis.MyNamespace;

MyNamespace.MyClass = class MyClass {}
// main.js
import "./namespace.js";
import "./class.js";

console.log(globalThis.MyNamespace.MyClass);

and compiling with the following command line:

./compiler.exe --js namespace.js --js class.js --js main.js --entry_point main.js --formatting PRETTY_PRINT --compilation_level ADVANCED --js_output_file out.js

produces the following output (note the undefined reference to globalThis.g.h, logging undefined):

globalThis.g = {};
console.log(globalThis.g.h);

The expected output is this (logging a class):

globalThis.g = {};
globalThis.g.h = class {
};
console.log(globalThis.g.h);

This can be worked around by changing the contents of class.js to:

globalThis.MyNamespace.MyClass = class MyClass {}

In other words the problem appears to be that Closure Compiler does not realise that const MyNamespace = globalThis.MyNamespace is aliasing a globally visible object, and so assigning to MyNamespace.MyClass is incorrectly deemed to be dead code. By assigning to globalThis directly it works correctly. This also only happens in ADVANCED mode - other modes like SIMPLE are not affected (presumably because they do not attempt dead code elimination).

This affects our commercial game development tool Construct (www.construct.net). Without the workaround, Closure Compiler deletes the entire class - all methods, properties, etc. - obviously breaking the output as one of the source code classes has been deleted.

AshleyScirra avatar Jun 22 '24 13:06 AshleyScirra