-
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
[ES6] bug: minifying const variable with inline parameter reuses same variable name for const and var, giving 'n is not defined' error #2842
Comments
Regression from Workaround:
|
@alexlamsl This is a case where the
|
Thanks, that's useful to know! Both inline=false and inline=1 work, it only gives errors on inline >= 2. |
@kzc may be the variable name collision logic of |
Above my pay grade. Can you suggest a simple fix? |
OT - function inlining is a lot trickier than I first thought. So many bloody edge cases. |
Let me finish my $day_job in a couple of hours, and I'll see what I can do. |
@kzc So the simplest fix would be to change |
FWIW, here's a slighly more reduced test case: (function() {
function inlinedFunction(data) {
return data[data[0]];
}
function testMinify() {
if (true) {
const data = inlinedFunction([1, 2, 3]);
console.log(data);
}
}
return testMinify();
})(); |
Then we'd lose There must be way to identify whether symbols within the function to be inlined conflict with any non- Let me think about it. |
They should be using |
Most new projects favor |
I haven't looked at the 186 170 downloads in the last day |
In which case, they are on their own - I have no plans to support |
@alexlamsl so, does that mean uglify-es will not get bug fixes/new features from now on? |
@krassx you are more than welcomed to work on I will review and take Pull Request on both branches, but my primary focus is a stable and usable |
@alexlamsl Correct me if I'm wrong... For the benefit of those not familiar with the uglify code base, this harmony branch bug (a.k.a.
|
@kzc (3) does not really fix the underlying cause of this issue - it just so happens the order of |
I was just in the process of making a comment edit. ;-) Edit: Technically option (2) would be also be required if option (3) were to be implemented. |
And perhaps the best option:
|
Jokes aside - I think we are getting close to the point where the issue of block scopes can no longer be relied on half-hearted workarounds within Certainly not something I would undertake lightly. |
@kzc if you really want to tackle (2), here's what I can contribute to your efforts: --- a/lib/compress.js
+++ b/lib/compress.js
@@ -4718,10 +4718,15 @@ merge(Compressor.prototype, {
in_loop = [];
} else if (scope instanceof AST_SymbolRef) {
if (scope.fixed_value() instanceof AST_Scope) return false;
+ } else if (scope.block_scope) {
+ scope = scope.block_scope;
}
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
var inline = compressor.option("inline");
+console.error(self.print_to_string());
+console.error(scope.TYPE, scope.var_names());
+console.error();
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop); $ uglifyjs test.js -bc
function(data){return data[data[0]]}([1,2,3])
Scope { data: true, inlinedFunction: true, console: true }
function(data){return data[data[0]]}([1,2,3])
Function { inlinedFunction: true, console: true, arguments: true }
!function() {
(function() {
{
const data = (data = [ 1, 2, 3 ])[data[0]];
console.log(data);
}
var data;
})();
}(); This is what I meant in #2842 (comment) |
@alexlamsl I wasn't kidding. You're doing a fantastic job maintaining and improving uglify in your free time and you should be compensated for it.
I'll let someone else deal with it. Now that |
I found a nice way to fix this. But it's going to take quite some work. There's already block-scope support in inlining functions, but it's only used for catch blocks.
I propose changing that variable name to
However, it will be quite some work because compress.js destroys and creates blocks like they don't have any scope! For example, our I'm currently working on finding places where |
Due to a bug in UglifyJS (mishoo/UglifyJS#2842) we should disable function inlining to avoid falling into this issue. the uglifyjs-webpack-plugin module is considering to move to the maintained fork of UglifyJS (terser: https://github.com/fabiosantoscode/terser): - webpack-contrib/uglifyjs-webpack-plugin#264 - webpack-contrib/uglifyjs-webpack-plugin#296 But until that happens I'd propose to disable function inlining.
Due to a bug in UglifyJS (mishoo/UglifyJS#2842) we should disable function inlining to avoid falling into this issue. the uglifyjs-webpack-plugin module is considering to move to the maintained fork of UglifyJS (terser: https://github.com/fabiosantoscode/terser): - webpack-contrib/uglifyjs-webpack-plugin#264 - webpack-contrib/uglifyjs-webpack-plugin#296 But until that happens I'd propose to disable function inlining.
Due to a bug in UglifyJS (mishoo/UglifyJS#2842) we should disable function inlining to avoid falling into this issue. the uglifyjs-webpack-plugin module is considering to move to the maintained fork of UglifyJS (terser: https://github.com/fabiosantoscode/terser): - webpack-contrib/uglifyjs-webpack-plugin#264 - webpack-contrib/uglifyjs-webpack-plugin#296 But until that happens I'd propose to disable function inlining.
UglifyJsPlugin will inline single-use functions by default. This can result in an error stating `TypeError: Assignment to constant variable`. To work around this, the function is reused since there was an opportunity to do so anyway. mishoo/UglifyJS#2842 (comment)
UglifyJsPlugin will inline single-use functions by default. This can result in an error stating `TypeError: Assignment to constant variable`. To work around this, the function is reused since there was an opportunity to do so anyway. mishoo/UglifyJS#2842 (comment)
* chore(account): fixed TypeError for accounts with 3+ tokens UglifyJsPlugin will inline single-use functions by default. This can result in an error stating `TypeError: Assignment to constant variable`. To work around this, the function is reused since there was an opportunity to do so anyway. mishoo/UglifyJS#2842 (comment) * chore(webpack): prevent uglify from inlining single-use functions
Note: this issue is also causing a problem with function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
} This, when inlined, results in something like this (minified): function u(t) {
return o = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function o(t) {
return typeof t
} : function o(t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
}, o(t)
} When executed in the browser (e.g. with browserify), this can cause all kinds of trouble, like overwriting the local I don't see this behavior anymore in |
@larsgw latest version of If not, please follow the issue template & file a new issue with a reproducible test case. |
To avoid bug in uglify-es@3.3.9 that reuses const names and causes Uncaught TypeError: Assignment to constant variable. Expected as a regression from 3.3.7 according to mishoo/UglifyJS#2842 (comment)
Seems like this issue should be resolved now: - mishoo/UglifyJS#2842 (comment)
Seems like this issue should be resolved now: - mishoo/UglifyJS#2842 (comment)
Seems like this issue should be resolved now: - mishoo/UglifyJS#2842 (comment)
* Add terraform and deployment scripts * Hotfix errors due to minifying js assets 1. It seems that using shorthand generator function definitions in objects (for src/slang/interpreter.ts) will result in a minified file where the generator method replaced by a function. `yield` calls in this generator therefore raise an uncaught syntax error in the browser. See: webpack/webpack#7566 2. A known issue with causes reuse of const variables in the same scope. See: mishoo/UglifyJS#2842 * Fix workspace-green css * Add profile variable to terraform config * Fix runInContext not finishing in minified js * Fix more instances of method shorthand bugs * Use dynamic class name for greenscreen * Format playground component * Add console.log to report version
Original example now works correctly in $ uglify-js input.js -bmc
var test = function() {
var n = {
children: n = [ 1, 2, 3 ],
count: n.reduce(function(n, t) {
return n + t;
})
};
this.someFunction && this.someFunction(n);
}(); Works even if $ uglify-js input.js -bmc varify=false
var test = function() {
{
const t = {
children: n = [ 1, 2, 3 ],
count: n.reduce(function(n, t) {
return n + t;
})
};
this.someFunction && this.someFunction(t);
}
var n;
}(); |
Fixes #346. This is a workaround for a bug in uglifyjs2 (mishoo/UglifyJS#2842), which can cause name collisions when a function with arguments is inlined. This can cause an unintended shadowing of a `var` or `let`, or a `TypeError: Assignment to constant variable` in case of a `const`.
Bug report or feature request?
bug
ES5 or ES6+ input?
ES6
Uglify version (
uglifyjs -V
)uglify-es 3.3.8
JavaScript input
The
uglifyjs
CLI command executed orminify()
options used.uglifyjs -b -c -m -- test.js
JavaScript output or error produced.
Chrome gives an 'Uncaught ReferenceError: n is not defined' error on line 5 when the minified output is pasted into the console and run, because it's trying to assign to 'n' as a variable and a constant.
The minified output looks like the following:
Actually encountered it elsewhere, but this is as simple as I can get the test case. Both the inlined function and the containing function seem to need to use their variables twice, otherwise it's all optimized away. The conditional is also necessary, though it doesn't have to be
if(true)
, just using that as an example.The text was updated successfully, but these errors were encountered: