added --self to easily get a browser-runnable version of UglifyJS
authorMihai Bazon <mihai@bazon.net>
Mon, 8 Oct 2012 09:55:18 +0000 (12:55 +0300)
committerMihai Bazon <mihai@bazon.net>
Mon, 8 Oct 2012 09:55:18 +0000 (12:55 +0300)
README.md
bin/uglifyjs2
lib/ast.js
tools/node.js

index 5eb28ba..8599307 100644 (file)
--- a/README.md
+++ b/README.md
@@ -66,6 +66,15 @@ The available options are:
     --acorn            Use Acorn for parsing.                            [boolean]
     --spidermonkey     Assume input fles are SpiderMonkey AST format (as JSON).
                                                                          [boolean]
+    --self             Build itself (UglifyJS2) as a library (implies
+                       --wrap=UglifyJS --export-all)                     [boolean]
+    --wrap             Embed everything in a big function, making the “exports”
+                       and “global” variables available. You need to pass an
+                       argument to this option to specify the name that your
+                       module will take when included in, say, a browser.
+                                                                          [string]
+    --export-all       Only used when --wrap, this tells UglifyJS to add code to
+                       automatically export all globals.                 [boolean]
     -v, --verbose      Verbose                                           [boolean]
 
 Specify `--output` (`-o`) to declare the output file.  Otherwise the output
index 17f82b5..ef87b65 100755 (executable)
@@ -43,6 +43,10 @@ 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("self", "Build itself (UglifyJS2) as a library (implies --wrap=UglifyJS --export-all)")
+    .describe("wrap", "Embed everything in a big function, making the “exports” and “global” variables available. \
+You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser.")
+    .describe("export-all", "Only used when --wrap, this tells UglifyJS to add code to automatically export all globals.")
     .describe("v", "Verbose")
 
     .alias("p", "prefix")
@@ -61,6 +65,9 @@ because of dead code removal or cascading statements into sequences.")
     .string("c")
     .string("d")
     .string("comments")
+    .string("wrap")
+    .boolean("export-all")
+    .boolean("self")
     .boolean("v")
     .boolean("stats")
     .boolean("acorn")
@@ -121,6 +128,15 @@ if (ARGS.comments) {
 
 var files = ARGS._.slice();
 
+if (ARGS.self) {
+    if (files.length > 0) {
+        sys.error("WARN: Ignoring input files since --self was passed");
+    }
+    files = UglifyJS.FILES;
+    if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
+    ARGS.export_all = true;
+}
+
 var ORIG_MAP = ARGS.in_source_map;
 
 if (ORIG_MAP) {
@@ -204,6 +220,10 @@ if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){
     TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
 });
 
+if (ARGS.wrap) {
+    TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
+}
+
 var SCOPE_IS_NEEDED = COMPRESS || MANGLE;
 
 if (SCOPE_IS_NEEDED) {
index 2b2467c..f44fa3a 100644 (file)
@@ -248,7 +248,46 @@ var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_
 }, AST_Block);
 
 var AST_Toplevel = DEFNODE("Toplevel", "globals", {
-    $documentation: "The toplevel scope"
+    $documentation: "The toplevel scope",
+    wrap_commonjs: function(name, export_all) {
+        var self = this;
+        if (export_all) {
+            self.figure_out_scope();
+            var to_export = [];
+            self.walk(new TreeWalker(function(node){
+                if (node instanceof AST_SymbolDeclaration && node.definition().global) {
+                    to_export.push(node.name);
+                }
+            }));
+        }
+        var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
+        wrapped_tl = parse(wrapped_tl);
+        wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
+            if (node instanceof AST_SimpleStatement) {
+                node = node.body;
+                if (node instanceof AST_String) switch (node.getValue()) {
+                  case "$ORIG":
+                    return new AST_BlockStatement(self);
+                  case "$EXPORTS":
+                    var body = [];
+                    to_export.forEach(function(name){
+                        body.push(new AST_SimpleStatement({
+                            body: new AST_Assign({
+                                left: new AST_Sub({
+                                    expression: new AST_SymbolRef({ name: "exports" }),
+                                    property: new AST_String({ value: name }),
+                                }),
+                                operator: "=",
+                                right: new AST_SymbolRef({ name: name }),
+                            }),
+                        }));
+                    });
+                    return new AST_BlockStatement({ body: body });
+                }
+            }
+        }));
+        return wrapped_tl;
+    }
 }, AST_Scope);
 
 var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
index 4abfa34..44fcbe4 100644 (file)
@@ -35,15 +35,21 @@ function load_global(file) {
     }
 };
 
-load_global("../lib/utils.js");
-load_global("../lib/ast.js");
-load_global("../lib/parse.js");
-load_global("../lib/transform.js");
-load_global("../lib/scope.js");
-load_global("../lib/output.js");
-load_global("../lib/compress.js");
-load_global("../lib/sourcemap.js");
-load_global("../lib/mozilla-ast.js");
+var FILES = exports.FILES = [
+    "../lib/utils.js",
+    "../lib/ast.js",
+    "../lib/parse.js",
+    "../lib/transform.js",
+    "../lib/scope.js",
+    "../lib/output.js",
+    "../lib/compress.js",
+    "../lib/sourcemap.js",
+    "../lib/mozilla-ast.js"
+].map(function(file){
+    return path.join(path.dirname(fs.realpathSync(__filename)), file);
+});
+
+FILES.forEach(load_global);
 
 UglifyJS.AST_Node.warn_function = function(txt) {
     sys.error("WARN: " + txt);