aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMihai Bazon <mihai@bazon.net>2012-10-05 15:22:12 +0300
committerMihai Bazon <mihai@bazon.net>2012-10-05 15:22:12 +0300
commite88dcc3819bd5af933d124fc5bf2b021366d5f28 (patch)
tree493bf6e62c3535f39250edcd7923ad37f45d4569
parentecd9f21467c32b6a0076a99bdd895cf37244683a (diff)
downloadtracifyjs-e88dcc3819bd5af933d124fc5bf2b021366d5f28.tar.gz
tracifyjs-e88dcc3819bd5af933d124fc5bf2b021366d5f28.zip
added --acorn and --spidermonkey options
-rw-r--r--README.md47
-rwxr-xr-xbin/uglifyjs280
2 files changed, 95 insertions, 32 deletions
diff --git a/README.md b/README.md
index ce5e05ed..252a9c28 100644
--- a/README.md
+++ b/README.md
@@ -23,8 +23,9 @@ files.
The available options are:
--source-map Specify an output file where to generate source map.
+ [string]
--source-map-root The path to the original source to be included in the
- source map.
+ source map. [string]
--in-source-map Input source map, useful if you're compressing JS that was
generated from some other original code.
-p, --prefix Skip prefix for original filenames that appear in source
@@ -49,12 +50,15 @@ The available options are:
compression is on, because of dead code removal or
cascading statements into sequences. [string]
--stats Display operations run time on STDERR. [boolean]
+ --acorn Use Acorn for parsing. [boolean]
+ --spidermonkey Assume input fles are SpiderMonkey AST format (as JSON).
+ [boolean]
-v, --verbose Verbose [boolean]
Specify `--output` (`-o`) to declare the output file. Otherwise the output
goes to STDOUT.
-### Source map options
+## Source map options
UglifyJS2 can generate a source map file, which is highly useful for
debugging your compressed JavaScript. To get a source map, pass
@@ -83,7 +87,7 @@ mapping will refer to `http://foo.com/src/js/file1.js` and
as the source map root, and the original files as `js/file1.js` and
`js/file2.js`).
-#### Composed source map
+### Composed source map
When you're compressing JS code that was output by a compiler such as
CoffeeScript, mapping to the JS code won't be too helpful. Instead, you'd
@@ -98,7 +102,7 @@ To use this feature you need to pass `--in-source-map
to the file containing the generated JS, so if that's correct you can omit
input files from the command line.
-### Mangler options
+## Mangler options
To enable the mangler you need to pass `--mangle` (`-m`). Optionally you
can pass `-m sort` (we'll possibly have other flags in the future) in order
@@ -115,7 +119,7 @@ comma-separated list of names. For example:
to prevent the `require`, `exports` and `$` names from being changed.
-### Compressor options
+## Compressor options
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
you can pass a comma-separated list of options. Options are in the form
@@ -184,7 +188,7 @@ will evaluate references to them to the value itself and drop unreachable
code as usual. The possible downside of this approach is that the build
will contain the `const` declarations.
-### Beautifier options
+## Beautifier options
The code generator tries to output shortest code possible by default. In
case you want beautified output, pass `--beautify` (`-b`). Optionally you
@@ -242,3 +246,34 @@ discarded by the compressor as not referenced.
The safest comments where to place copyright information (or other info that
needs to me kept in the output) are comments attached to toplevel nodes.
+
+## Support for the SpiderMonkey AST
+
+UglifyJS2 has its own abstract syntax tree format; for
+[practical reasons](http://lisperator.net/blog/uglifyjs-why-not-switching-to-spidermonkey-ast/)
+we can't easily change to using the SpiderMonkey AST internally. However,
+UglifyJS now has a converter which can import a SpiderMonkey AST.
+
+For example [Acorn](https://github.com/marijnh/acorn) is a super-fast parser
+that produces a SpiderMonkey AST. It has a small CLI utility that parses
+one file and dumps the AST in JSON on the standard output. To use UglifyJS
+to mangle and compress that:
+
+ acorn file.js | uglifyjs2 --spidermonkey -m -c
+
+The `--spidermonkey` option tells UglifyJS that all input files are not
+JavaScript, but JS code described in SpiderMonkey AST in JSON. Therefore we
+don't use our own parser in this case, but just transform that AST into our
+internal AST.
+
+### Use Acorn for parsing
+
+More for fun, I added the `--acorn` option which will use Acorn to do all
+the parsing. If you pass this option, UglifyJS will `require("acorn")`. At
+the time I'm writing this it needs
+[this commit](https://github.com/mishoo/acorn/commit/17c0d189c7f9ce5447293569036949b5d0a05fef)
+in Acorn to support multiple input files and properly generate source maps.
+
+Acorn is really fast (e.g. 250ms instead of 380ms on some 650K code), but
+converting the SpiderMonkey tree that Acorn produces takes another 150ms so
+in total it's a bit more than just using UglifyJS's own parser.
diff --git a/bin/uglifyjs2 b/bin/uglifyjs2
index cdecb848..17f82b58 100755
--- a/bin/uglifyjs2
+++ b/bin/uglifyjs2
@@ -7,6 +7,7 @@ var UglifyJS = require("../tools/node");
var sys = require("util");
var optimist = require("optimist");
var fs = require("fs");
+var acorn;
var ARGS = optimist
.usage("$0 input1.js [input2.js ...] [options]\n\
Use a single dash to read input from the standard input.\
@@ -40,6 +41,8 @@ Note that currently not *all* comments can be kept when compression is on, \
because of dead code removal or cascading statements into sequences.")
.describe("stats", "Display operations run time on STDERR.")
+ .describe("acorn", "Use Acorn for parsing.")
+ .describe("spidermonkey", "Assume input fles are SpiderMonkey AST format (as JSON).")
.describe("v", "Verbose")
.alias("p", "prefix")
@@ -60,40 +63,25 @@ because of dead code removal or cascading statements into sequences.")
.string("comments")
.boolean("v")
.boolean("stats")
+ .boolean("acorn")
+ .boolean("spidermonkey")
.wrap(80)
.argv
;
-function normalize(o) {
- for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
- o[i.replace(/-/g, "_")] = o[i];
- delete o[i];
- }
-}
-
-normalize(ARGS);
-
if (ARGS.h || ARGS.help) {
sys.puts(optimist.help());
process.exit(0);
}
-function getOptions(x) {
- x = ARGS[x];
- if (!x) return null;
- var ret = {};
- if (x !== true) {
- x.replace(/^\s+|\s+$/g).split(/\s*,+\s*/).forEach(function(opt){
- var a = opt.split(/\s*[=:]\s*/);
- ret[a[0]] = a.length > 1 ? new Function("return(" + a[1] + ")")() : true;
- });
- normalize(ret);
- }
- return ret;
+if (ARGS.acorn) {
+ acorn = require("acorn");
}
+normalize(ARGS);
+
var COMPRESS = getOptions("c");
var MANGLE = getOptions("m");
var BEAUTIFY = getOptions("b");
@@ -190,13 +178,32 @@ files.forEach(function(file) {
file = file.replace(/^\/+/, "").split(/\/+/).slice(ARGS.p).join("/");
}
time_it("parse", function(){
- TOPLEVEL = UglifyJS.parse(code, {
- filename: file,
- toplevel: TOPLEVEL
- });
+ if (ARGS.spidermonkey) {
+ var program = JSON.parse(code);
+ if (!TOPLEVEL) TOPLEVEL = program;
+ else TOPLEVEL.body = TOPLEVEL.body.concat(program.body);
+ }
+ else if (ARGS.acorn) {
+ TOPLEVEL = acorn.parse(code, {
+ locations : true,
+ trackComments : true,
+ sourceFile : file,
+ program : TOPLEVEL
+ });
+ }
+ else {
+ TOPLEVEL = UglifyJS.parse(code, {
+ filename: file,
+ toplevel: TOPLEVEL
+ });
+ };
});
});
+if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){
+ TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
+});
+
var SCOPE_IS_NEEDED = COMPRESS || MANGLE;
if (SCOPE_IS_NEEDED) {
@@ -256,6 +263,27 @@ if (ARGS.stats) {
/* -----[ functions ]----- */
+function normalize(o) {
+ for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
+ o[i.replace(/-/g, "_")] = o[i];
+ delete o[i];
+ }
+}
+
+function getOptions(x) {
+ x = ARGS[x];
+ if (!x) return null;
+ var ret = {};
+ if (x !== true) {
+ x.replace(/^\s+|\s+$/g).split(/\s*,+\s*/).forEach(function(opt){
+ var a = opt.split(/\s*[=:]\s*/);
+ ret[a[0]] = a.length > 1 ? new Function("return(" + a[1] + ")")() : true;
+ });
+ normalize(ret);
+ }
+ return ret;
+}
+
function read_whole_file(filename) {
if (filename == "-") {
// XXX: this sucks. How does one read the whole STDIN
@@ -279,4 +307,4 @@ function time_it(name, cont) {
else STATS[name] = spent;
}
return ret;
-};
+}