Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing debug code from inside a function using Closure Compiler simple optimisations

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:

  1. This requires var DEBUG to be defined in each file, which is bad practice.
  2. 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.
  3. 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?

like image 624
Brian Nickel Avatar asked Jul 09 '12 20:07

Brian Nickel


People also ask

How does Closure compiler work?

The Closure Compiler is a tool for making JavaScript download and run faster. Instead of compiling from a source language to machine code, it compiles from JavaScript to better JavaScript. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left.

What is the purpose of advanced mode in closure compiler?

Solution(By Examveda Team) In Advanced mode, the Closure Compiler rewrites the JavaScript by renaming variables and functions from longer descriptive names to single letters to save file size, and it inlines functions, coalescing them into single functions wherever it determines that it can.

Which of the following are the three compilation levels that can be applied to the JavaScript code to define the degree of compression and optimization required?

The value of this parameter indicates the degree of compression and optimization to apply to your JavaScript. There are three possible compilation levels: WHITESPACE_ONLY , SIMPLE_OPTIMIZATIONS , and ADVANCED_OPTIMIZATIONS .


1 Answers

Use @define annotation:

@define {boolean}

DEBUG = true;

And compile with option

--define="DEBUG=false"

like image 89
user2712511 Avatar answered Sep 21 '22 14:09

user2712511