Skip to content

Loading…

Remove calls to console.* #293

Open
wants to merge 3 commits into from

4 participants

@sjhewitt

This change removes calls to console.* statements as requested in #124 (I couldn't get this code to attach to that issue...)

It does so by replacing statements that call console methods with an empty block to be removed later by the squeeze function.

The caveat is that it only fully removes console function calls if they are executed as statements. If the calls are made elsewhere in the tree then they will just be replaced with 0. For example, the following boolean expression:

console.log("a") && console.log("b")

will be compressed to:

0&&0

Also, the function arguments will be removed so users should be aware that if an argument is a function call, it won't be executed. For example, the foo function call will be totally removed in the following example:

console.log("this is bad", foo())

This can be executed from the commandline by adding the --no-console flag

@davidlevy

Do you know when it will be committed in the master ?

@iliakan

Looks good so far.. How about to make it external to uglify? So I can remove anything or can modify it.. Maybe add hooks to default uglifier? Right now I can replace default squeezer by hijacking require(..)

e.g uglify-console.js:

var uglify = require("uglify-js"), 
    pro = uglify.uglify;

pro.ast_squeeze_console = function(ast) {
        var w = pro.ast_walker(), walk = w.walk, scope;
         return w.with_walkers({
                "stat": function(stmt) {
                        if(stmt[0] === "call" && stmt[1][0] == "dot" && stmt[1][1] instanceof Array && stmt[1][1][0] == 'name' && stmt[1][1][1] == "console") {
                                return ["block"];
                        }
                        return ["stat", walk(stmt)];
                },
                "call": function(expr, args) {
                        if (expr[0] == "dot" && expr[1] instanceof Array && expr[1][0] == 'name' && expr[1][1] == "console") {
                                return ["atom", "0"];
                        }
                }
        }, function() {
                return walk(ast);
        });
};

var ast_squeeze = pro.ast_squeeze;

pro.ast_squeeze = function() {
  var ast = ast_squeeze.apply(this, arguments);
  ast = pro.ast_squeeze_console(ast);
  return ast;
}

require('./uglify.js');
@sjhewitt

@iliakan I'm not convinced by that method of monkey-patching the ast_squeeze function. If you're going to be using it from within some node script you have control over, you might as well include the ast_squeeze_console function and make your own custom version of the uglify function that is in uglify.js:

var uglify = require('uglify-js');
function ast_squeeze_console(){ ... };

function myUglify(orig_code, options){
    options || (options = {});
    var jsp = uglify.parser;
    var pro = uglify.uglify;

    var ast = jsp.parse(orig_code, options.strict_semicolons); // parse code and get the initial AST
    ast = ast_squeeze_console(ast); // get rid of console statements
    ast = pro.ast_mangle(ast, options.mangle_options); // get a new AST with mangled names
    ast = pro.ast_squeeze(ast, options.squeeze_options); // get an AST with compression optimizations
    var final_code = pro.gen_code(ast, options.gen_options); // compressed code here
    return final_code;
};

For command-line usage via bin/uglify some kind of plugin architecture could be useful, but I don't hold out much hope of it being included.

@simenbrekken

I believe you can simply use sed to comment out any console statements before passing the script to UglifyJS.

sed -E 's/(console\.)/\/\/\1/g' script.js | uglifyjs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Showing with 41 additions and 5 deletions.
  1. +7 −0 bin/uglifyjs
  2. +3 −1 lib/process.js
  3. +20 −0 lib/squeeze-more.js
  4. +1 −0 test/unit/compress/expected/console.js
  5. +3 −0 test/unit/compress/test/console.js
  6. +7 −4 test/unit/scripts.js
View
7 bin/uglifyjs
@@ -15,6 +15,7 @@ var options = {
squeeze: true,
make_seqs: true,
dead_code: true,
+ no_console: false,
verbose: false,
show_copyright: true,
out_same_file: false,
@@ -76,6 +77,9 @@ out: while (args.length > 0) {
case "--no-dead-code":
options.dead_code = false;
break;
+ case "--no-console":
+ options.no_console = true;
+ break;
case "--no-copyright":
case "-nc":
options.show_copyright = false;
@@ -281,6 +285,9 @@ function squeeze_it(code) {
if (options.lift_vars) {
ast = time_it("lift", function(){ return pro.ast_lift_variables(ast); });
}
+ if (options.no_console) {
+ ast = time_it("console", function(){ return pro.ast_squeeze_console(ast); });
+ }
if (options.mangle) ast = time_it("mangle", function(){
return pro.ast_mangle(ast, {
toplevel : options.mangle_toplevel,
View
4 lib/process.js
@@ -2006,4 +2006,6 @@ exports.split_lines = split_lines;
exports.MAP = MAP;
// keep this last!
-exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
+var more = require("./squeeze-more");
+exports.ast_squeeze_more = more.ast_squeeze_more;
+exports.ast_squeeze_console = more.ast_squeeze_console;
View
20 lib/squeeze-more.js
@@ -66,4 +66,24 @@ function ast_squeeze_more(ast) {
});
};
+function ast_squeeze_console(ast) {
+ var w = pro.ast_walker(), walk = w.walk, scope;
+ return w.with_walkers({
+ "stat": function(stmt) {
+ if(stmt[0] === "call" && stmt[1][0] == "dot" && stmt[1][1] instanceof Array && stmt[1][1][0] == 'name' && stmt[1][1][1] == "console") {
+ return ["block"];
+ }
+ return ["stat", walk(stmt)];
+ },
+ "call": function(expr, args) {
+ if (expr[0] == "dot" && expr[1] instanceof Array && expr[1][0] == 'name' && expr[1][1] == "console") {
+ return ["atom", "0"];
+ }
+ }
+ }, function() {
+ return walk(ast);
+ });
+};
+
exports.ast_squeeze_more = ast_squeeze_more;
+exports.ast_squeeze_console = ast_squeeze_console;
View
1 test/unit/compress/expected/console.js
@@ -0,0 +1 @@
+var f=function(a,b,c){return a+b+c}
View
3 test/unit/compress/test/console.js
@@ -0,0 +1,3 @@
+console.log("test")
+
+var f = function(a, b, c){console.log(a,b,c);return a + b + c;};
View
11 test/unit/scripts.js
@@ -9,11 +9,14 @@ var Script = process.binding('evals').Script;
var scriptsPath = __dirname;
-function compress(code) {
+function compress(code, squeezeConsole) {
var ast = jsp.parse(code);
ast = pro.ast_mangle(ast);
+ if(squeezeConsole) {
+ ast = pro.ast_squeeze_console(ast);
+ }
ast = pro.ast_squeeze(ast, { no_warnings: true });
- ast = pro.ast_squeeze_more(ast);
+ ast = pro.ast_squeeze_more(ast);
return pro.gen_code(ast);
};
@@ -25,13 +28,13 @@ function getTester(script) {
var testPath = path.join(testDir, script);
var expectedPath = path.join(expectedDir, script);
var content = fs.readFileSync(testPath, 'utf-8');
- var outputCompress = compress(content);
+ var outputCompress = compress(content, script==="console.js");
// Check if the noncompressdata is larger or same size as the compressed data
test.ok(content.length >= outputCompress.length);
// Check that a recompress gives the same result
- var outputReCompress = compress(content);
+ var outputReCompress = compress(content, script==="console.js");
test.equal(outputCompress, outputReCompress);
// Check if the compressed output is what is expected
Something went wrong with that request. Please try again.