在缩小期间排除调试JavaScript代码

时间:2010-05-29 09:31:22

标签: javascript compression minify google-closure-compiler

我正在研究缩小JavaScript代码的不同方法,包括常规JSMin,Packer和YUI解决方案。我真的对新的Google Closure Compiler感兴趣,因为它看起来非常强大。

我注意到Dean Edwards packer有一个功能可以排除以三个分号开头的代码行。这对于排除调试代码很方便。例如:

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

我花了一些时间来清理我的代码库,并希望添加这样的提示以轻松排除调试代码。为此做准备,我想弄清楚这是否是最佳解决方案,还是有其他技术。

因为我还没有选择如何缩小,我想以一种与我最终使用的最小化器兼容的方式清理代码。所以我的问题是这些:

  1. 使用分号是一种标准技术,还是有其他方法可以做到?

  2. Packer是唯一提供此功能的解决方案吗?

  3. 其他解决方案是否也可以适应这种方式,或者他们是否有其他方法来实现这一目标?

  4. 我最终可能会开始使用Closure Compiler。现在有什么我应该做的准备吗?

11 个答案:

答案 0 :(得分:57)

这是闭包编译器的(终极)答案:

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

这甚至适用于SIMPLE_OPTIMIZATIONS,不需要--define=

答案 1 :(得分:25)

这是我使用Closure Compiler的内容。首先,您需要定义一个这样的DEBUG变量:

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

它使用JS注释进行闭包,您可以阅读in the documentation

现在,只要你想要一些只调试代码,只需将它包装在if语句中,如下所示:

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

在编译发布代码时,添加以下编译命令:--define='DEBUG=false' - 调试语句中的任何代码都将完全不在编译文件中。

答案 2 :(得分:6)

在这种情况下,一个好的解决方案可能是js-build-tools,它支持'条件编译'。

简而言之,您可以使用

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

您可以在其中定义编译指示,例如debug

然后在构建它时(它有一个ant任务)

//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"/>

答案 3 :(得分:2)

如果在高级模式下使用Closure Compiler,您可以执行以下操作:

if (DEBUG) console.log = function() {}

然后编译器将删除所有的console.log调用。当然,您需要在命令行中--define变量DEBUG

但是,这仅适用于高级模式。如果您使用简单模式,则需要在源文件上运行预处理器。

为什么不考虑Dojo Toolkit?它具有内置的基于注释的编译指示,可以根据构建包含/排除代码部分。此外,它与高级模式下的Closure Compiler兼容(参见下面的链接)!

http://dojo-toolkit.33424.n3.nabble.com/file/n2636749/Using_the_Dojo_Toolkit_with_the_Closure_Compiler.pdf?by-user=t

答案 4 :(得分:2)

尽管这是一个老问题。我今天偶然发现了同样的问题,发现可以使用CompilerOptions来实现。

我跟着this thread

我们在服务器上运行编译器,然后将代码发送到客户端。这在简单模式下适用于我们。

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();
}

它将删除对logger.debug,logger.dev等的所有调用...等等

答案 5 :(得分:2)

将逻辑添加到代码中您登录控制台的每个位置都会使调试和维护变得更加困难。

如果您已经要为生产代码添加构建步骤,则可以随时在顶部添加另一个文件,将noop方法转换为console.log = console.debug = console.info = function(){};

类似的东西:

console

理想情况下,您只需删除任何{{1}}方法,但如果您仍然保留它们但不使用它们,则这可能是最容易使用的方法。

答案 6 :(得分:1)

如果您使用UglifyJS2,则可以使用 drop_console 参数删除console。*函数。

答案 7 :(得分:1)

我和@ marcel-korpel在一起。不是完美但有效。缩小之前替换调试说明。正则表达式在许多地方都有效。留意未公开的界限。

/console\.[^;]*/gm

适用于:

;;;     console.log("Starting process");
console.log("Starting process");
console.dir("Starting process");;;;;
console.log("Starting "+(1+2)+" processes"); iamok('good');
console.log('Message ' +
    'with new line'
);
console.group("a");
console.groupEnd();
swtich(input){
    case 1 : alert('ok'); break;
    default: console.warn("Fatal error"); break;
}

不能工作:

console.log("instruction without semicolon")
console.log("semicolon in ; string");

答案 8 :(得分:0)

到目前为止,我还没有考虑缩小,但是这种行为可以使用简单的正则表达式来完成:

s/;;;.*//g

在没有任何内容的情况下替换三个分号之后的所有内容,因此在缩小之前将其丢弃。您可以在运行缩小工具之前运行sed(或类似工具),如下所示:

sed 's/;;;.*//g' < infile.js > outfile.js

BTW,如果您想知道打包版本或缩小版本是否“更好”,请阅读this comparison of JavaScript compression methods

答案 9 :(得分:0)

我使用了以下自制的stuf:

// Uncomment to enable debug messages
// var debug = true;

function ShowDebugMessage(message) {
    if (debug) {
        alert(message);
    }
}

因此,当您声明变量debug设置为true时,所有ShowDebugMessage()次调用也会调用alert()。因此,只需在代码中使用它,忘记ifdef之类的条件或调试输出行的手动注释。

答案 10 :(得分:0)

我在我的React应用程序中使用它:

OnInit

换句话说,if (process.env.REACT_APP_STAGE === 'PROD') console.log = function no_console() {}; 在产品环境中将不返回任何内容。