From dd8286bce152125d18a0af13a6088049303f2993 Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Mon, 8 Oct 2012 12:55:18 +0300 Subject: [PATCH] added --self to easily get a browser-runnable version of UglifyJS --- README.md | 9 +++++++++ bin/uglifyjs2 | 20 ++++++++++++++++++++ lib/ast.js | 41 ++++++++++++++++++++++++++++++++++++++++- tools/node.js | 24 +++++++++++++++--------- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5eb28bae..85993076 100644 --- 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 diff --git a/bin/uglifyjs2 b/bin/uglifyjs2 index 17f82b58..ef87b657 100755 --- a/bin/uglifyjs2 +++ b/bin/uglifyjs2 @@ -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) { diff --git a/lib/ast.js b/lib/ast.js index 2b2467cf..f44fa3ae 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -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", { diff --git a/tools/node.js b/tools/node.js index 4abfa34a..44fcbe47 100644 --- a/tools/node.js +++ b/tools/node.js @@ -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); -- 2.34.1