Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db66eca958 | ||
|
|
916faf0a48 | ||
|
|
f36e4e9a78 | ||
|
|
fdf8b5eb71 | ||
|
|
de7ec7f1b7 | ||
|
|
3c8a0bdff4 | ||
|
|
9e8ba27dcd | ||
|
|
719a8fd102 | ||
|
|
3a22e917de | ||
|
|
a9af2c9e62 | ||
|
|
31e99cebe7 | ||
|
|
a5b209470c | ||
|
|
e9a571b2a1 | ||
|
|
8bf83f42ea | ||
|
|
522566ea80 | ||
|
|
297af47c89 | ||
|
|
faa354f5ca | ||
|
|
1529ab965a | ||
|
|
605f330e69 | ||
|
|
f0909bdc8f | ||
|
|
c13e7e621d | ||
|
|
ad071f8017 | ||
|
|
c058d8b9cd | ||
|
|
1d8871a092 |
30
README.md
30
README.md
@@ -12,7 +12,14 @@ Chrome and probably Safari).
|
|||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
|
|
||||||
From NPM:
|
First make sure you have installed the latest version of [node.js](http://nodejs.org/)
|
||||||
|
(You may need to restart your computer after this step).
|
||||||
|
|
||||||
|
From NPM for use as a command line app:
|
||||||
|
|
||||||
|
npm install uglify-js -g
|
||||||
|
|
||||||
|
From NPM for programmatic use:
|
||||||
|
|
||||||
npm install uglify-js
|
npm install uglify-js
|
||||||
|
|
||||||
@@ -42,6 +49,9 @@ The available options are:
|
|||||||
[string]
|
[string]
|
||||||
--source-map-root The path to the original source to be included in the
|
--source-map-root The path to the original source to be included in the
|
||||||
source map. [string]
|
source map. [string]
|
||||||
|
--source-map-url The path to the source map to be added in //@
|
||||||
|
sourceMappingURL. Defaults to the value passed with
|
||||||
|
--source-map. [string]
|
||||||
--in-source-map Input source map, useful if you're compressing JS that was
|
--in-source-map Input source map, useful if you're compressing JS that was
|
||||||
generated from some other original code.
|
generated from some other original code.
|
||||||
-p, --prefix Skip prefix for original filenames that appear in source
|
-p, --prefix Skip prefix for original filenames that appear in source
|
||||||
@@ -78,8 +88,9 @@ The available options are:
|
|||||||
[string]
|
[string]
|
||||||
--export-all Only used when --wrap, this tells UglifyJS to add code to
|
--export-all Only used when --wrap, this tells UglifyJS to add code to
|
||||||
automatically export all globals. [boolean]
|
automatically export all globals. [boolean]
|
||||||
|
--lint Display some scope warnings [boolean]
|
||||||
-v, --verbose Verbose [boolean]
|
-v, --verbose Verbose [boolean]
|
||||||
-V, --version Print version number and exits. [boolean]
|
-V, --version Print version number and exit. [boolean]
|
||||||
|
|
||||||
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
||||||
goes to STDOUT.
|
goes to STDOUT.
|
||||||
@@ -158,8 +169,8 @@ the available options (all are `true` by default, except `hoist_vars`):
|
|||||||
- `sequences` -- join consecutive simple statements using the comma operator
|
- `sequences` -- join consecutive simple statements using the comma operator
|
||||||
- `properties` -- rewrite property access using the dot notation, for
|
- `properties` -- rewrite property access using the dot notation, for
|
||||||
example `foo["bar"] → foo.bar`
|
example `foo["bar"] → foo.bar`
|
||||||
- `dead-code` -- remove unreachable code
|
- `dead_code` -- remove unreachable code
|
||||||
- `drop-debugger` -- remove `debugger;` statements
|
- `drop_debugger` -- remove `debugger;` statements
|
||||||
- `unsafe` -- apply "unsafe" transformations (discussion below)
|
- `unsafe` -- apply "unsafe" transformations (discussion below)
|
||||||
- `conditionals` -- apply optimizations for `if`-s and conditional
|
- `conditionals` -- apply optimizations for `if`-s and conditional
|
||||||
expressions
|
expressions
|
||||||
@@ -172,11 +183,11 @@ the available options (all are `true` by default, except `hoist_vars`):
|
|||||||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
||||||
statically determine the condition
|
statically determine the condition
|
||||||
- `unused` -- drop unreferenced functions and variables
|
- `unused` -- drop unreferenced functions and variables
|
||||||
- `hoist-funs` -- hoist function declarations
|
- `hoist_funs` -- hoist function declarations
|
||||||
- `hoist-vars` -- hoist `var` declarations (this is `false` by default
|
- `hoist_vars` -- hoist `var` declarations (this is `false` by default
|
||||||
because it seems to increase the size of the output in general)
|
because it seems to increase the size of the output in general)
|
||||||
- `if-return` -- optimizations for if/return and if/continue
|
- `if_return` -- optimizations for if/return and if/continue
|
||||||
- `join-vars` -- join consecutive `var` statements
|
- `join_vars` -- join consecutive `var` statements
|
||||||
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
||||||
and `x = something(), x` into `x = something()`
|
and `x = something(), x` into `x = something()`
|
||||||
- `warnings` -- display warnings when dropping unreachable code or unused
|
- `warnings` -- display warnings when dropping unreachable code or unused
|
||||||
@@ -324,9 +335,10 @@ There's a single toplevel function which combines all the steps. If you
|
|||||||
don't need additional customization, you might want to go with `minify`.
|
don't need additional customization, you might want to go with `minify`.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
// see "fromString" below if you need to pass code instead of file name
|
|
||||||
var result = UglifyJS.minify("/path/to/file.js");
|
var result = UglifyJS.minify("/path/to/file.js");
|
||||||
console.log(result.code); // minified output
|
console.log(result.code); // minified output
|
||||||
|
// if you need to pass code instead of file name
|
||||||
|
var result = UglifyJS.minify("var b = function () {};", {fromString: true});
|
||||||
|
|
||||||
You can also compress multiple files:
|
You can also compress multiple files:
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ mangling you need to use `-c` and `-m`.\
|
|||||||
")
|
")
|
||||||
.describe("source-map", "Specify an output file where to generate source map.")
|
.describe("source-map", "Specify an output file where to generate source map.")
|
||||||
.describe("source-map-root", "The path to the original source to be included in the source map.")
|
.describe("source-map-root", "The path to the original source to be included in the source map.")
|
||||||
|
.describe("source-map-url", "The path to the source map to be added in //@ sourceMappingURL. Defaults to the value passed with --source-map.")
|
||||||
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
|
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
|
||||||
.describe("p", "Skip prefix for original filenames that appear in source maps. \
|
.describe("p", "Skip prefix for original filenames that appear in source maps. \
|
||||||
For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
|
For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
|
||||||
@@ -63,6 +64,7 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
|
|
||||||
.string("source-map")
|
.string("source-map")
|
||||||
.string("source-map-root")
|
.string("source-map-root")
|
||||||
|
.string("source-map-url")
|
||||||
.string("b")
|
.string("b")
|
||||||
.string("m")
|
.string("m")
|
||||||
.string("c")
|
.string("c")
|
||||||
@@ -277,7 +279,7 @@ output = output.get();
|
|||||||
|
|
||||||
if (SOURCE_MAP) {
|
if (SOURCE_MAP) {
|
||||||
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
||||||
output += "\n//@ sourceMappingURL=" + ARGS.source_map;
|
output += "\n/*\n//@ sourceMappingURL=" + (ARGS.source_map_url || ARGS.source_map) + "\n*/";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OUTPUT_FILE) {
|
if (OUTPUT_FILE) {
|
||||||
|
|||||||
@@ -863,6 +863,11 @@ var AST_Undefined = DEFNODE("Undefined", null, {
|
|||||||
value: (function(){}())
|
value: (function(){}())
|
||||||
}, AST_Atom);
|
}, AST_Atom);
|
||||||
|
|
||||||
|
var AST_Hole = DEFNODE("Hole", null, {
|
||||||
|
$documentation: "A hole in an array",
|
||||||
|
value: (function(){}())
|
||||||
|
}, AST_Atom);
|
||||||
|
|
||||||
var AST_Infinity = DEFNODE("Infinity", null, {
|
var AST_Infinity = DEFNODE("Infinity", null, {
|
||||||
$documentation: "The `Infinity` value",
|
$documentation: "The `Infinity` value",
|
||||||
value: 1/0
|
value: 1/0
|
||||||
|
|||||||
@@ -628,7 +628,10 @@ merge(Compressor.prototype, {
|
|||||||
case "typeof": return typeof ev(e);
|
case "typeof": return typeof ev(e);
|
||||||
case "void": return void ev(e);
|
case "void": return void ev(e);
|
||||||
case "~": return ~ev(e);
|
case "~": return ~ev(e);
|
||||||
case "-": return -ev(e);
|
case "-":
|
||||||
|
e = ev(e);
|
||||||
|
if (e === 0) throw def;
|
||||||
|
return -e;
|
||||||
case "+": return +ev(e);
|
case "+": return +ev(e);
|
||||||
}
|
}
|
||||||
throw def;
|
throw def;
|
||||||
@@ -669,12 +672,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(){
|
def(AST_SymbolRef, function(){
|
||||||
var d = this.definition();
|
var d = this.definition();
|
||||||
if (d && d.constant) {
|
if (d && d.constant && d.init) return ev(d.init);
|
||||||
var orig = d.orig[0];
|
|
||||||
if (orig) orig = orig.init[0];
|
|
||||||
orig = orig && orig.value;
|
|
||||||
if (orig) return ev(orig);
|
|
||||||
}
|
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
@@ -1566,6 +1564,9 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "String":
|
case "String":
|
||||||
|
if (self.args.length == 0) return make_node(AST_String, self, {
|
||||||
|
value: ""
|
||||||
|
});
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
left: self.args[0],
|
left: self.args[0],
|
||||||
operator: "+",
|
operator: "+",
|
||||||
@@ -1736,7 +1737,8 @@ merge(Compressor.prototype, {
|
|||||||
if (self.left instanceof AST_String
|
if (self.left instanceof AST_String
|
||||||
&& self.left.value == "undefined"
|
&& self.left.value == "undefined"
|
||||||
&& self.right instanceof AST_UnaryPrefix
|
&& self.right instanceof AST_UnaryPrefix
|
||||||
&& self.right.operator == "typeof") {
|
&& self.right.operator == "typeof"
|
||||||
|
&& compressor.option("unsafe")) {
|
||||||
if (!(self.right.expression instanceof AST_SymbolRef)
|
if (!(self.right.expression instanceof AST_SymbolRef)
|
||||||
|| !self.right.expression.undeclared()) {
|
|| !self.right.expression.undeclared()) {
|
||||||
self.left = self.right.expression;
|
self.left = self.right.expression;
|
||||||
|
|||||||
@@ -375,6 +375,16 @@ function OutputStream(options) {
|
|||||||
if (start && !start._comments_dumped) {
|
if (start && !start._comments_dumped) {
|
||||||
start._comments_dumped = true;
|
start._comments_dumped = true;
|
||||||
var comments = start.comments_before;
|
var comments = start.comments_before;
|
||||||
|
|
||||||
|
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
|
||||||
|
// if this node is `return` or `throw`, we cannot allow comments before
|
||||||
|
// the returned or thrown value.
|
||||||
|
if (self instanceof AST_Exit &&
|
||||||
|
self.value && self.value.start.comments_before.length > 0) {
|
||||||
|
comments = (comments || []).concat(self.value.start.comments_before);
|
||||||
|
self.value.start.comments_before = [];
|
||||||
|
}
|
||||||
|
|
||||||
if (c.test) {
|
if (c.test) {
|
||||||
comments = comments.filter(function(comment){
|
comments = comments.filter(function(comment){
|
||||||
return c.test(comment.value);
|
return c.test(comment.value);
|
||||||
@@ -499,11 +509,23 @@ function OutputStream(options) {
|
|||||||
PARENS(AST_New, function(output){
|
PARENS(AST_New, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (no_constructor_parens(this, output)
|
if (no_constructor_parens(this, output)
|
||||||
&& (p instanceof AST_Dot // (new Date).getTime()
|
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
PARENS(AST_Number, function(output){
|
||||||
|
var p = output.parent();
|
||||||
|
if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
PARENS(AST_NaN, function(output){
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_PropAccess && p.expression === this)
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
function assign_and_conditional_paren_rules(output) {
|
function assign_and_conditional_paren_rules(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// !(a = false) → true
|
// !(a = false) → true
|
||||||
@@ -932,7 +954,7 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Dot, function(self, output){
|
DEFPRINT(AST_Dot, function(self, output){
|
||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
expr.print(output);
|
expr.print(output);
|
||||||
if (expr instanceof AST_Number) {
|
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
||||||
if (!/[xa-f.]/i.test(output.last())) {
|
if (!/[xa-f.]/i.test(output.last())) {
|
||||||
output.print(".");
|
output.print(".");
|
||||||
}
|
}
|
||||||
@@ -984,7 +1006,6 @@ function OutputStream(options) {
|
|||||||
if (len > 0) output.space();
|
if (len > 0) output.space();
|
||||||
a.forEach(function(exp, i){
|
a.forEach(function(exp, i){
|
||||||
if (i) output.comma();
|
if (i) output.comma();
|
||||||
if (!(exp instanceof AST_Undefined))
|
|
||||||
exp.print(output);
|
exp.print(output);
|
||||||
});
|
});
|
||||||
if (len > 0) output.space();
|
if (len > 0) output.space();
|
||||||
@@ -1036,6 +1057,7 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Undefined, function(self, output){
|
DEFPRINT(AST_Undefined, function(self, output){
|
||||||
output.print("void 0");
|
output.print("void 0");
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_Hole, noop);
|
||||||
DEFPRINT(AST_Infinity, function(self, output){
|
DEFPRINT(AST_Infinity, function(self, output){
|
||||||
output.print("1/0");
|
output.print("1/0");
|
||||||
});
|
});
|
||||||
@@ -1059,6 +1081,9 @@ function OutputStream(options) {
|
|||||||
if (output.option("ascii_only"))
|
if (output.option("ascii_only"))
|
||||||
str = output.to_ascii(str);
|
str = output.to_ascii(str);
|
||||||
output.print(str);
|
output.print(str);
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||||
|
output.print(" ");
|
||||||
});
|
});
|
||||||
|
|
||||||
function force_statement(stat, output) {
|
function force_statement(stat, output) {
|
||||||
|
|||||||
@@ -1131,7 +1131,7 @@ function parse($TEXT, options) {
|
|||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
if (allow_trailing_comma && is("punc", closing)) break;
|
if (allow_trailing_comma && is("punc", closing)) break;
|
||||||
if (is("punc", ",") && allow_empty) {
|
if (is("punc", ",") && allow_empty) {
|
||||||
a.push(new AST_Undefined({ start: S.token, end: S.token }));
|
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||||
} else {
|
} else {
|
||||||
a.push(expression(false));
|
a.push(expression(false));
|
||||||
}
|
}
|
||||||
@@ -1358,7 +1358,7 @@ function parse($TEXT, options) {
|
|||||||
left : left,
|
left : left,
|
||||||
operator : val,
|
operator : val,
|
||||||
right : maybe_assign(no_in),
|
right : maybe_assign(no_in),
|
||||||
end : peek()
|
end : prev()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
croak("Invalid assignment");
|
croak("Invalid assignment");
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
|| node instanceof AST_SymbolConst) {
|
|| node instanceof AST_SymbolConst) {
|
||||||
var def = scope.def_variable(node);
|
var def = scope.def_variable(node);
|
||||||
def.constant = node instanceof AST_SymbolConst;
|
def.constant = node instanceof AST_SymbolConst;
|
||||||
def = tw.parent();
|
def.init = tw.parent().value;
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolCatch) {
|
else if (node instanceof AST_SymbolCatch) {
|
||||||
// XXX: this is wrong according to ECMA-262 (12.4). the
|
// XXX: this is wrong according to ECMA-262 (12.4). the
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"main": "tools/node.js",
|
"main": "tools/node.js",
|
||||||
"version": "2.2.3",
|
"version": "2.2.5",
|
||||||
"engines": { "node" : ">=0.4.0" },
|
"engines": { "node" : ">=0.4.0" },
|
||||||
"maintainers": [{
|
"maintainers": [{
|
||||||
"name": "Mihai Bazon",
|
"name": "Mihai Bazon",
|
||||||
|
|||||||
12
test/compress/arrays.js
Normal file
12
test/compress/arrays.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
holes_and_undefined: {
|
||||||
|
input: {
|
||||||
|
x = [1, 2, undefined];
|
||||||
|
y = [1, , 2, ];
|
||||||
|
z = [1, undefined, 3];
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x=[1,2,void 0];
|
||||||
|
y=[1,,2];
|
||||||
|
z=[1,void 0,3];
|
||||||
|
}
|
||||||
|
}
|
||||||
17
test/compress/issue-105.js
Normal file
17
test/compress/issue-105.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
typeof_eq_undefined: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe: false
|
||||||
|
};
|
||||||
|
input: { a = typeof b.c != "undefined" }
|
||||||
|
expect: { a = "undefined" != typeof b.c }
|
||||||
|
}
|
||||||
|
|
||||||
|
typeof_eq_undefined_unsafe: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe: true
|
||||||
|
};
|
||||||
|
input: { a = typeof b.c != "undefined" }
|
||||||
|
expect: { a = b.c !== void 0 }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user