Skip to content

Commit ef5f7fc

Browse files
authored
workaround various IE quirks (#5084)
fixes #5081
1 parent 902997b commit ef5f7fc

33 files changed

+477
-311
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
matrix:
1111
options:
1212
- '-mb braces'
13-
- '--ie8 -c'
13+
- '--ie -c'
1414
- '-mc'
1515
- '-p acorn --toplevel -mco spidermonkey'
1616
- '--toplevel -mc passes=3,pure_getters,unsafe'

README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ a double dash to prevent input files being used as option arguments:
111111
-d, --define <expr>[=value] Global definitions.
112112
-e, --enclose [arg[:value]] Embed everything in a big function, with configurable
113113
argument(s) & value(s).
114-
--ie8 Support non-standard Internet Explorer 8.
115-
Equivalent to setting `ie8: true` in `minify()`
114+
--ie Support non-standard Internet Explorer.
115+
Equivalent to setting `ie: true` in `minify()`
116116
for `compress`, `mangle` and `output` options.
117117
By default UglifyJS will not try to be IE-proof.
118118
--keep-fnames Do not mangle/drop function names. Useful for
@@ -502,7 +502,7 @@ if (result.error) throw result.error;
502502
- `compress` (default: `{}`) — pass `false` to skip compressing entirely.
503503
Pass an object to specify custom [compress options](#compress-options).
504504

505-
- `ie8` (default: `false`) — set to `true` to support IE8.
505+
- `ie` (default: `false`) — enable workarounds for Internet Explorer bugs.
506506

507507
- `keep_fnames` (default: `false`) — pass `true` to prevent discarding or mangling
508508
of function names. Useful for code relying on `Function.prototype.name`.
@@ -566,7 +566,6 @@ if (result.error) throw result.error;
566566
},
567567
nameCache: null, // or specify a name cache object
568568
toplevel: false,
569-
ie8: false,
570569
warnings: false,
571570
}
572571
```
@@ -795,9 +794,8 @@ to be `false` and all symbol names will be omitted.
795794
variables (`"vars"`) in the top level scope (`false` by default, `true` to drop
796795
both unreferenced functions and variables)
797796

798-
- `typeofs` (default: `true`) — Transforms `typeof foo == "undefined"` into
799-
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
800-
earlier versions due to known issues.
797+
- `typeofs` (default: `true`) — compress `typeof` expressions, e.g.
798+
`typeof foo == "undefined" → void 0 === foo`
801799

802800
- `unsafe` (default: `false`) — apply "unsafe" transformations (discussion below)
803801

bin/uglifyjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ function process_option(name, no_value) {
101101
" --config-file <file> Read minify() options from JSON file.",
102102
" -d, --define <expr>[=value] Global definitions.",
103103
" -e, --enclose [arg[,...][:value[,...]]] Embed everything in a big function, with configurable argument(s) & value(s).",
104-
" --ie8 Support non-standard Internet Explorer 8.",
104+
" --ie Support non-standard Internet Explorer.",
105105
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
106106
" --name-cache <file> File to hold mangled name mappings.",
107107
" --rename Force symbol expansion.",
@@ -110,6 +110,7 @@ function process_option(name, no_value) {
110110
" --source-map [options] Enable source map/specify source map options.",
111111
" --timings Display operations run time on STDERR.",
112112
" --toplevel Compress and/or mangle variables in toplevel scope.",
113+
" --v8 Support non-standard Chrome & Node.js.",
113114
" --validate Perform validation during AST manipulations.",
114115
" --verbose Print diagnostic messages.",
115116
" --warn Print warning messages.",
@@ -145,9 +146,11 @@ function process_option(name, no_value) {
145146
options[name] = read_value();
146147
break;
147148
case "annotations":
149+
case "ie":
148150
case "ie8":
149151
case "timings":
150152
case "toplevel":
153+
case "v8":
151154
case "validate":
152155
case "webkit":
153156
options[name] = true;

lib/compress.js

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function Compressor(options, false_by_default) {
7070
hoist_funs : false,
7171
hoist_props : !false_by_default,
7272
hoist_vars : false,
73-
ie8 : false,
73+
ie : false,
7474
if_return : !false_by_default,
7575
imports : !false_by_default,
7676
inline : !false_by_default,
@@ -206,7 +206,7 @@ merge(Compressor.prototype, {
206206
var passes = +this.options.passes || 1;
207207
var min_count = 1 / 0;
208208
var stopping = false;
209-
var mangle = { ie8: this.option("ie8") };
209+
var mangle = { ie: this.option("ie") };
210210
for (var pass = 0; pass < passes; pass++) {
211211
node.figure_out_scope(mangle);
212212
if (pass > 0 || this.option("reduce_vars"))
@@ -513,7 +513,7 @@ merge(Compressor.prototype, {
513513
if (scope.uses_arguments) scope.each_argname(function(node) {
514514
node.definition().last_ref = false;
515515
});
516-
if (compressor.option("ie8")) scope.variables.each(function(def) {
516+
if (compressor.option("ie")) scope.variables.each(function(def) {
517517
var d = def.orig[0].definition();
518518
if (d !== def) d.fixed = false;
519519
});
@@ -2249,7 +2249,7 @@ merge(Compressor.prototype, {
22492249
return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs);
22502250
}
22512251
if (node instanceof AST_Function) {
2252-
return compressor.option("ie8") && node.name && lvalues.has(node.name.name);
2252+
return compressor.option("ie") && node.name && lvalues.has(node.name.name);
22532253
}
22542254
if (node instanceof AST_ObjectIdentity) return symbol_in_lvalues(node, parent);
22552255
if (node instanceof AST_PropAccess) {
@@ -4208,7 +4208,7 @@ merge(Compressor.prototype, {
42084208

42094209
AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) {
42104210
if (!compressor.option("global_defs")) return this;
4211-
this.figure_out_scope({ ie8: compressor.option("ie8") });
4211+
this.figure_out_scope({ ie: compressor.option("ie") });
42124212
return this.transform(new TreeTransformer(function(node) {
42134213
var def = node._find_defs(compressor, "");
42144214
if (!def) return;
@@ -5672,7 +5672,7 @@ merge(Compressor.prototype, {
56725672
if (node instanceof AST_Call) {
56735673
var exp = node.expression;
56745674
var tail = exp.tail_node();
5675-
if (!(tail instanceof AST_LambdaExpression)) return;
5675+
if (!(tail instanceof AST_LambdaExpression)) return walk_node_with_expr(node);
56765676
if (exp !== tail) exp.expressions.slice(0, -1).forEach(function(node) {
56775677
node.walk(tw);
56785678
});
@@ -5788,6 +5788,7 @@ merge(Compressor.prototype, {
57885788
pop();
57895789
return true;
57905790
}
5791+
if (node instanceof AST_Sub) return walk_node_with_expr(node);
57915792
if (node instanceof AST_Switch) {
57925793
node.expression.walk(tw);
57935794
var save = segment;
@@ -5886,6 +5887,15 @@ merge(Compressor.prototype, {
58865887
pop();
58875888
return true;
58885889
}
5890+
5891+
function walk_node_with_expr(node) {
5892+
descend();
5893+
if (compressor.option("ie")) {
5894+
var sym = root_expr(node.expression);
5895+
if (sym instanceof AST_SymbolRef) sym.walk(tw);
5896+
}
5897+
return true;
5898+
}
58895899
});
58905900
tw.directives = Object.create(compressor.directives);
58915901
self.walk(tw);
@@ -6235,7 +6245,7 @@ merge(Compressor.prototype, {
62356245
});
62366246
tw.directives = Object.create(compressor.directives);
62376247
self.walk(tw);
6238-
var drop_fn_name = compressor.option("keep_fnames") ? return_false : compressor.option("ie8") ? function(def) {
6248+
var drop_fn_name = compressor.option("keep_fnames") ? return_false : compressor.option("ie") ? function(def) {
62396249
return !compressor.exposed(def) && def.references.length == def.replaced;
62406250
} : function(def) {
62416251
if (!(def.id in in_use_ids)) return true;
@@ -6247,7 +6257,7 @@ merge(Compressor.prototype, {
62476257
return !ref.in_arg;
62486258
});
62496259
};
6250-
if (compressor.option("ie8")) initializations.each(function(init, id) {
6260+
if (compressor.option("ie")) initializations.each(function(init, id) {
62516261
if (id in in_use_ids) return;
62526262
init.forEach(function(init) {
62536263
init.walk(new TreeWalker(function(node) {
@@ -6535,7 +6545,7 @@ merge(Compressor.prototype, {
65356545
head.push(def);
65366546
}
65376547
} else if (compressor.option("functions")
6538-
&& !compressor.option("ie8")
6548+
&& !compressor.option("ie")
65396549
&& drop_sym
65406550
&& var_defs[sym.id] == 1
65416551
&& sym.assignments == 0
@@ -7652,7 +7662,7 @@ merge(Compressor.prototype, {
76527662
});
76537663

76547664
function fn_name_unused(fn, compressor) {
7655-
if (!fn.name || !compressor.option("ie8")) return true;
7665+
if (!fn.name || !compressor.option("ie")) return true;
76567666
var def = fn.name.definition();
76577667
if (compressor.exposed(def)) return false;
76587668
return all(def.references, function(sym) {
@@ -7969,7 +7979,7 @@ merge(Compressor.prototype, {
79697979
var alternative = this.alternative.drop_side_effect_free(compressor);
79707980
if (consequent === this.consequent && alternative === this.alternative) return this;
79717981
var exprs;
7972-
if (compressor.option("ie8")) {
7982+
if (compressor.option("ie")) {
79737983
exprs = [];
79747984
if (consequent instanceof AST_Function) {
79757985
exprs.push(consequent);
@@ -7998,7 +8008,7 @@ merge(Compressor.prototype, {
79988008
node.consequent = consequent;
79998009
node.alternative = alternative;
80008010
}
8001-
if (!compressor.option("ie8")) return node;
8011+
if (!compressor.option("ie")) return node;
80028012
if (node) exprs.push(node);
80038013
return exprs.length == 0 ? null : make_sequence(this, exprs);
80048014
});
@@ -9411,7 +9421,7 @@ merge(Compressor.prototype, {
94119421
return arg.value;
94129422
}).join() + "){" + self.args[self.args.length - 1].value + "})";
94139423
var ast = parse(code);
9414-
var mangle = { ie8: compressor.option("ie8") };
9424+
var mangle = { ie: compressor.option("ie") };
94159425
ast.figure_out_scope(mangle);
94169426
var comp = new Compressor(compressor.options);
94179427
ast = ast.transform(comp);
@@ -10465,7 +10475,7 @@ merge(Compressor.prototype, {
1046510475
&& self.right.operator == "typeof") {
1046610476
var expr = self.right.expression;
1046710477
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
10468-
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
10478+
: !(expr instanceof AST_PropAccess && compressor.option("ie"))) {
1046910479
self.right = expr;
1047010480
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
1047110481
if (self.operator.length == 2) self.operator += "=";
@@ -11079,7 +11089,7 @@ merge(Compressor.prototype, {
1107911089
}
1108011090

1108111091
OPT(AST_SymbolRef, function(self, compressor) {
11082-
if (!compressor.option("ie8")
11092+
if (!compressor.option("ie")
1108311093
&& is_undeclared_ref(self)
1108411094
// testing against `self.scope.uses_with` is an optimization
1108511095
&& !(self.scope.resolve().uses_with && compressor.find_parent(AST_With))) {
@@ -11121,7 +11131,7 @@ merge(Compressor.prototype, {
1112111131
single_use = false;
1112211132
} else if (fixed.has_side_effects(compressor)) {
1112311133
single_use = false;
11124-
} else if (compressor.option("ie8") && fixed instanceof AST_Class) {
11134+
} else if (compressor.option("ie") && fixed instanceof AST_Class) {
1112511135
single_use = false;
1112611136
}
1112711137
if (single_use) fixed.parent_scope = self.scope;

lib/minify.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ function minify(files, options) {
7676
annotations: undefined,
7777
compress: {},
7878
enclose: false,
79+
ie: false,
7980
ie8: false,
8081
keep_fnames: false,
8182
mangle: {},
@@ -96,7 +97,7 @@ function minify(files, options) {
9697
var timings = options.timings && { start: Date.now() };
9798
if (options.rename === undefined) options.rename = options.compress && options.mangle;
9899
if (options.annotations !== undefined) set_shorthand("annotations", options, [ "compress", "output" ]);
99-
if (options.ie8) set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
100+
if (options.ie || options.ie8) set_shorthand("ie", options, [ "compress", "mangle", "output" ]);
100101
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
101102
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle" ]);
102103
if (options.v8) set_shorthand("v8", options, [ "mangle", "output" ]);
@@ -106,7 +107,7 @@ function minify(files, options) {
106107
options.mangle = defaults(options.mangle, {
107108
cache: options.nameCache && (options.nameCache.vars || {}),
108109
eval: false,
109-
ie8: false,
110+
ie: false,
110111
keep_fnames: false,
111112
properties: false,
112113
reserved: [],

lib/output.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function OutputStream(options) {
5656
braces : false,
5757
comments : false,
5858
galio : false,
59-
ie8 : false,
59+
ie : false,
6060
indent_level : 4,
6161
indent_start : 0,
6262
inline_script : true,
@@ -193,7 +193,7 @@ function OutputStream(options) {
193193
case "\t": return "\\t";
194194
case "\b": return "\\b";
195195
case "\f": return "\\f";
196-
case "\x0B": return options.ie8 ? "\\x0B" : "\\v";
196+
case "\x0B": return options.ie ? "\\x0B" : "\\v";
197197
case "\u2028": return "\\u2028";
198198
case "\u2029": return "\\u2029";
199199
case "\ufeff": return "\\ufeff";
@@ -1290,7 +1290,7 @@ function OutputStream(options) {
12901290
function make_then(self, output) {
12911291
var b = self.body;
12921292
if (output.option("braces") && !(b instanceof AST_Const || b instanceof AST_Let)
1293-
|| output.option("ie8") && b instanceof AST_Do)
1293+
|| output.option("ie") && b instanceof AST_Do)
12941294
return make_block(b, output);
12951295
// The squeezer replaces "block"-s that contain only a single
12961296
// statement with the statement itself; technically, the AST
@@ -1515,7 +1515,7 @@ function OutputStream(options) {
15151515
var expr = self.expression;
15161516
expr.print(output);
15171517
var prop = self.property;
1518-
if (output.option("ie8") && RESERVED_WORDS[prop]) {
1518+
if (output.option("ie") && RESERVED_WORDS[prop]) {
15191519
output.print(self.optional ? "?.[" : "[");
15201520
output.add_mapping(self.end);
15211521
output.print_string(prop);
@@ -1702,7 +1702,7 @@ function OutputStream(options) {
17021702
var quote = self.start && self.start.quote;
17031703
if (self.private) {
17041704
output.print_name(key);
1705-
} else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
1705+
} else if (RESERVED_WORDS[key] ? !output.option("ie") : is_identifier_string(key)) {
17061706
if (quote && output.option("keep_quoted_props")) {
17071707
output.print_string(key, quote);
17081708
} else {

lib/scope.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ function is_lhs(node, parent) {
118118
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
119119
options = defaults(options, {
120120
cache: null,
121-
ie8: false,
121+
ie: false,
122122
});
123123

124124
// pass 1: setup scope chaining and handle definitions
@@ -211,7 +211,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
211211
entangle(defun, scope);
212212
} else if (node instanceof AST_SymbolLambda) {
213213
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
214-
if (options.ie8) def.defun = defun.parent_scope.resolve();
214+
if (options.ie) def.defun = defun.parent_scope.resolve();
215215
} else if (node instanceof AST_SymbolLet) {
216216
var def = scope.def_variable(node);
217217
if (exported) def.exported = true;
@@ -351,7 +351,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
351351
self.walk(tw);
352352

353353
// pass 3: fix up any scoping issue with IE8
354-
if (options.ie8) self.walk(new TreeWalker(function(node) {
354+
if (options.ie) self.walk(new TreeWalker(function(node) {
355355
if (node instanceof AST_SymbolCatch) {
356356
var scope = node.thedef.defun;
357357
if (scope.name instanceof AST_SymbolLambda && scope.name.name == node.name) {
@@ -572,7 +572,7 @@ AST_Symbol.DEFMETHOD("definition", function() {
572572
function _default_mangler_options(options) {
573573
options = defaults(options, {
574574
eval : false,
575-
ie8 : false,
575+
ie : false,
576576
keep_fnames : false,
577577
reserved : [],
578578
toplevel : false,

test/compress/classes.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@ issue_4705: {
11571157

11581158
issue_4720: {
11591159
options = {
1160-
ie8: true,
1160+
ie: true,
11611161
reduce_vars: true,
11621162
toplevel: true,
11631163
unused: true,
@@ -1629,7 +1629,7 @@ issue_4951_2: {
16291629

16301630
issue_4962_1: {
16311631
options = {
1632-
ie8: true,
1632+
ie: true,
16331633
inline: true,
16341634
reduce_vars: true,
16351635
unused: true,
@@ -1656,7 +1656,7 @@ issue_4962_1: {
16561656

16571657
issue_4962_2: {
16581658
options = {
1659-
ie8: true,
1659+
ie: true,
16601660
inline: true,
16611661
reduce_vars: true,
16621662
unused: true,

0 commit comments

Comments
 (0)