Exclude debug JavaScript code during minification

19,939

Solution 1

here's the (ultimate) answer for closure compiler :

/** @const */
var LOG = false;
...
LOG && log('hello world !'); // compiler will remove this line
...

this will even work with SIMPLE_OPTIMIZATIONS and no --define= is necessary !

Solution 2

Here's what I use with Closure Compiler. First, you need to define a DEBUG variable like this:

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

It's using the JS annotation for closure, which you can read about in the documentation.

Now, whenever you want some debug-only code, just wrap it in an if statement, like so:

if (DEBUG) {
  console.log("Running in DEBUG mode");
}

When compiling your code for release, add the following your compilation command: --define='DEBUG=false' -- any code within the debug statement will be completely left out of the compiled file.

Solution 3

A good solution in this case might be js-build-tools which supports 'conditional compilation'.

In short you can use comments such as

// #ifdef debug
var trace = debug.getTracer("easyXDM.Rpc");
trace("constructor");
// #endif

where you define a pragma such as debug.

Then when building it (it has an ant-task)

//this file will not have the debug code
<preprocess infile="work/easyXDM.combined.js" outfile="work/easyXDM.js"/>
//this file will        
<preprocess infile="work/easyXDM.combined.js" outfile="work/easyXDM.debug.js" defines="debug"/>

Solution 4

Adding logic to every place in your code where you are logging to the console makes it harder to debug and maintain.

If you are already going to add a build step for your production code, you could always add another file at the top that turns your console methods into noop's.

Something like:

console.log = console.debug = console.info = function(){};

Ideally, you'd just strip out any console methods, but if you are keeping them in anyway but not using them, this is probably the easiest to work with.

Solution 5

Even though its an old question. I stumbled upon the same issue today and found that it can be achieved using CompilerOptions.

I followed this thread.

We run the compiler, from Java, on our server before sending the code to the client. This worked for us in Simple mode.

private String compressWithClosureCompiler(final String code) {
    final Compiler compiler = new Compiler();
    final CompilerOptions options = new CompilerOptions();
    Logger.getLogger("com.google.javascript.jscomp").setLevel(Level.OFF);
    if (compressRemovesLogging) {
        options.stripNamePrefixes = ImmutableSet.of("logger");
        options.stripNameSuffixes = ImmutableSet.of("debug", "dev", "info", "error",
                "warn", "startClock", "stopClock", "dir");
    }
    CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);

    final JSSourceFile extern = JSSourceFile.fromCode("externs.js", "");
    final JSSourceFile input = JSSourceFile.fromCode("input.js", code);
    compiler.compile(extern, input, options);
    return compiler.toSource();
}

It will remove all the calls to logger.debug, logger.dev...etc.etc

Share:
19,939

Related videos on Youtube

Tauren
Author by

Tauren

Software engineer

Updated on December 12, 2020

Comments

  • Tauren
    Tauren over 3 years

    I'm looking into different ways to minify my JavaScript code including the regular JSMin, Packer, and YUI solutions. I'm really interested in the new Google Closure Compiler, as it looks exceptionally powerful.

    I noticed that Dean Edwards packer has a feature to exclude lines of code that start with three semicolons. This is handy to exclude debug code. For instance:

    ;;;     console.log("Starting process");
    

    I'm spending some time cleaning up my codebase and would like to add hints like this to easily exclude debug code. In preparation for this, I'd like to figure out if this is the best solution, or if there are other techniques.

    Because I haven't chosen how to minify yet, I'd like to clean the code in a way that is compatible with whatever minifier I end up going with. So my questions are these:

    1. Is using the semicolons a standard technique, or are there other ways to do it?

    2. Is Packer the only solution that provides this feature?

    3. Can the other solutions be adapted to work this way as well, or do they have alternative ways of accomplishing this?

    4. I will probably start using Closure Compiler eventually. Is there anything I should do now that would prepare for it?

  • Palani
    Palani over 12 years
    Don't miss the annotation '/** @define {boolean} */', it wont work without that.
  • Matthew
    Matthew over 12 years
    This answer should be at the top. A bonus is that in advanced mode the log function would be stripped out as dead code.
  • hellectronic
    hellectronic almost 12 years
    This sounds realy usefull. But testing it on the online closure-compiler page and local does not have the effect.
  • ansiart
    ansiart over 11 years
    @hellectronic Actually it does work, you just need to put all of your code inside a closure, as otherwise the compiler thinks it's a global variable, and will not strip it out. This is probably best anyways so that you don't globalize any "use strict" statements
  • tim peterson
    tim peterson almost 11 years
    Can someone explain this answer a little more? i'm still new to closure compiler and don't really get whats going on in this code.
  • kares
    kares almost 11 years
    LOG is annotated as a constant (non changing value) - closure assumes it never changes thus when a LOG && ... statements is reached it can safely 'remove' the whole statement since it has no side effects - it will always end up as "false"
  • tim peterson
    tim peterson almost 11 years
    Hi @Kares, do you mean console.log('...') rather than log('...')? log() gives an error. Also, how does this work with multiple files, given as @anisart says, that it needs to be in a closure? You have to put your code above on each page?
  • tim peterson
    tim peterson almost 11 years
    A big downside to this method, unlike using the traditional console.log(), is that when LOG=truethe line number reported in the dev tools for log() is where this function was defined and not where it was invoked. So all messages are reported as being on the same line and not where they occurred. This is pretty suboptimal given that the line number of the message is often key for debugging.
  • kares
    kares almost 11 years
    @timpeterson this is only a concept - if you do not like it down vote it :) ... I personally do not care about line numbers (on the other side you can var log = console.log or even better you can make sure it's always executed in the context of console if needed) and it was written around the time when leaving bare console.log statements in your code was not very safe and portable.
  • user56reinstatemonica8
    user56reinstatemonica8 almost 10 years
    For anyone confused about how to make this work, here's an easy way: 1) plonk /** @const */ var LOG = false; at the top, after the Closure settings, before your code. 2) find/change console.log to LOG&&console.log in your code. All console.log calls will be removed by the compiler. However, for me this only works wiht "ADVANCED_OPTIMIZATIONS" mode