-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Property mangling should throw an error on non-property global references #5933
Comments
PTAL at #5934 I have implemented |
I don't think that's quite the same thing - this issue isn't about whether or not globals get mangled, it's about ensuring a failure occurs when encountering a global variable not written as a property. |
In addition, one of our assumptions on the input code is that you can prepend or append to the minified output, so (seemingly) undeclared variables are a natural occurance. One solution to preserve runtime behaviour is by not mangling property access on the global object, as shown #5934. An alternative approach to this is to have a feature whereby undeclared variables are linked to properties of the global object, i.e. your code with this feature enabled will become: globalThis.l = 1;
console.log(l); That would require |
If you do this: globalThis.l = 1;
console.log(l); then you need to make sure UglifyJS never chooses the name globalThis.MyGlobal = 1;
// 10,000 lines of code ...
function ShowMessage(message)
{
console.log(message, MyGlobal);
} then minifying to the following would be broken: globalThis.l = 1;
// 10,000 lines of code ...
function ShowMessage(l)
{
console.log(l, l);
} There might be other edge cases. I assumed the reason Closure Compiler didn't support this was because it was too difficult to implement and avoid such cases, as renaming non-property global variables uses the same namespace as local variables. Perhaps a solution would be to use a prefix for all global variables, e.g. globalThis._gl = 1;
// 10,000 lines of code ...
function ShowMessage(l)
{
console.log(l, _gl);
} I guess that would be a useful solution - although I can still imagine there are difficult edge cases - you have to choose a prefix that doesn't collide with any existing global variables, doesn't collide with any existing or chosen local variables, and is still sufficiently short enough to minify nicely. Closure Compiler's solution is reasonable in my view - it requires writing all globals as property accesses, and fails on undeclared variable names. It's better than leaving broken code as it means you find out the problem at minify time, rather than having to sift through potentially thousands of lines of broken minified code (i.e. fail fast principle). Perhaps Uglify could add the "fail on undeclared" mode as an option. |
Avoiding name collision is exactly what Closure Compiler has a habit of complaining about valid JavaScript code because it "knows better". As much as I appreciate they are put in place for good intentions, all these minor nuisances (false positives) will just render the tool unusable, at least for me. |
Uglify version (
uglifyjs -V
) v3.19.3JavaScript input
The
uglifyjs
CLI command executed orminify()
options used.uglifyjs input.js --mangle-props --beautify --output output.js
JavaScript output or error produced.
Explanation
In the case shown above, the code is written incorrectly for property mangling.
MyGlobal
is referred to both as a property on the global object (globalThis.MyGlobal
), and as a non-property variable access (MyGlobal
).Quite understandably, property mangling does not attempt to rename the latter reference - doing so could cause name collisions with local variables. However in this case UglifyJS merely silently produces broken code. In such cases it is better to actually throw an error.
This is what Closure Compiler does: if you pass the input script with arguments
./compiler.exe --js input.js --formatting PRETTY_PRINT --compilation_level ADVANCED --js_output_file output.js
, it throws an error on the second reference and does not produce output:The fix with both Closure Compiler and UglifyJS is to consistently write
globalThis.MyGlobal
, i.e. explicitly as a property of the global object, so property mangling works as expected with globals. However by throwing an error and pointing at the incorrect code, it makes it much easier to get this right, rather than dealing with a potentially large amount of minified output that does not work.Note this may be a breaking change, as the way UglifyJS currently works implicitly treats all non-property global references as externals that do not get renamed, and it's easy to imagine some use cases depending on this, so perhaps it should be an option (IMO, an opt-out rather than opt-in).
The text was updated successfully, but these errors were encountered: