Question

I am trying to get google closure compiler to remove some logging function calls from my javascript without any success. Here is my test code that reproduces what I am seeing

/** @define {boolean} */
var ENABLE_LOGGING = true;

(function() {
    function obj(name) {
        this.name = name;
    }   
    obj.prototype = { 
        log: ENABLE_LOGGING ?
            function(msg) { console.log(this.name + ': ' + msg); } : 
            function(msg) {}
    };  

    var A = new obj('bob');
    var B = new obj('tom');

    A.log('I am an object!');
    B.log('I am another object!');
})();

When I compile this with java -jar ./compiler.jar --define ENABLE_LOGGING=false --compilation_level ADVANCED_OPTIMIZATIONS --js test.js, it produces this output (pretty printed for clarity):

(function() {
  function a(a) {
    this.name = a;
  }
  a.prototype = {log:function() {
  }};
  var b = new a("tom");
  (new a("bob")).log("I am an object!");
  b.log("I am another object!");
})();

What would be the correct way to get closure compiler to leave out the logging code? Here it is leaving in a call to a function that does nothing.

Was it helpful?

Solution

"log" will never be eliminated, here is why:

To eliminate "log" it must be inlined.
It can't currently be inlined unless it can be devirtualized.
It can't be devirtualized unless it can be disambiguated.
It can't be disambiguated if a definition exists on a super class (https://code.google.com/p/closure-compiler/issues/detail?id=1184)
Object is a superclass.
Math is a namespace, defined as an Object.
Math has the property log.

You also need to do the following:
1) Remove the IFFE, method devirtualization only works on global type definitions
2) Move the ENABLE_LOGGING check to be inside the method. Devirtualization only works on function definitions and occurs before dead code elimination.

All of these restrictions can be avoided by using a local function definition instead of object method.

This has the effect you want:

/** @define {boolean} */
var ENABLE_LOGGING = false;

(function() {
    function obj(name) {
        this.name = name;
    }   
    var log = 
        ENABLE_LOGGING ?
            function(obj, msg) { console.log(obj.name + ': ' + msg); } : 
            function(obj, msg) {};

    var A = new obj('bob');
    var B = new obj('tom');

    log(A, 'I am an object!');
    log(B, 'I am another object!');
})();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top