I'm looking for a way to strip out debug code from functions so I can add test hooks to closures. I've read Google Closure Compiler advanced: remove code blocks at compile time and tested out removing debug code with the following:
/** @define {boolean} */
var DEBUG = true;
if (DEBUG) {
console.log('remove me');
}
Simple optimisation with --define='DEBUG=false'
reduces this to var DEBUG=!1;
. The same applies for this:
/** @const */
var DEBUG = false;
if (DEBUG) {
console.log('remove me');
}
Where I run into trouble is using this convention inside a function:
/** @const */
var DEBUG = false;
function logMe() {
if (DEBUG) {
console.log('remove me');
}
}
This reduces to the following:
var DEBUG=!1;function logMe(){DEBUG&&console.log("remove me")};
I would expect it to reduce further to:
var DEBUG=!1;function logMe(){};
Is there a reason this is not working as expected? I'm really just looking for a clean way to strip debug code and am not ready to take the plunge into advanced optimizations.
Update
Per @John's answer, I implemented my own compiler and have found that the following configuration will remove if (DEBUG) {}
from inside and outside the code for the case of a @define
:
CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
//options.setInlineConstantVars(true);
options.setInlineVariables(CompilerOptions.Reach.ALL);
options.setDefineToBooleanLiteral("DEBUG", false);
This works well enough for a single file with the following limitations:
- This requires
var DEBUG
to be defined in each file, which is bad practice. - When combining multiple files, you can only have a single
var DEBUG
or the compiler can't optimize around it. This could be avoided by compiling each file individually and merging them. - Because the value is defined at the beginning of the file, there's no flexibility to receive the value beforehand.
I've toyed with the idea of removing all var DEBUG
definitions from the files and injecting it into the source or extern before execution, but I've run into two issues:
- Defining it in extern appears to do nothing.
- Undefined
DEBUG
in the uncompiled code throws a reference error in the browser.
The ideal option would be to test window.DEBUG
, which does not throw a reference error. Unfortunately, while injecting /** @const */ var window = {}; /** @const */ window.DEBUG = false;
works at the top level, reducing if (window.DEBUG) {}
, the optimization is actually reverted if placed in a function.
Unless another compiler option works the only option that would really make sense is to go with window.DEBUG
and before compilation inject /** @const */ var DEBUG = false;
and to a global replace of /\bwindow.DEBUG\b/
with DEBUG
. Is there a better way?