我正在寻找一种从函数中删除调试代码的方法,这样我就可以在闭包中添加测试挂钩。我读了 Google Closure Compiler advanced: remove code blocks at compile time并测试了以下内容删除调试代码:
/** @define {boolean} */
var DEBUG = true;
if (DEBUG) {
console.log('remove me');
}
使用--define='DEBUG=false'
进行简单优化会将此优化减少到var DEBUG=!1;
。这同样适用于此:
/** @const */
var DEBUG = false;
if (DEBUG) {
console.log('remove me');
}
我遇到麻烦的地方是在函数中使用这个约定:
/** @const */
var DEBUG = false;
function logMe() {
if (DEBUG) {
console.log('remove me');
}
}
这减少到以下几点:
var DEBUG=!1;function logMe(){DEBUG&&console.log("remove me")};
我希望它能进一步减少到:
var DEBUG=!1;function logMe(){};
有没有理由不按预期工作?我真的只是在寻找一种简单的方法来剥离调试代码,而我还没有准备好接受高级优化。
更新
Per @ John的回答,我实现了自己的编译器,并发现以下配置将从代码内部和外部删除if (DEBUG) {}
@define
的情况:
CompilerOptions options = new CompilerOptions();
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
//options.setInlineConstantVars(true);
options.setInlineVariables(CompilerOptions.Reach.ALL);
options.setDefineToBooleanLiteral("DEBUG", false);
这对于具有以下限制的单个文件非常有效:
var DEBUG
,这是不好的做法。var DEBUG
,或者编译器无法对其进行优化。这可以通过单独编译每个文件并合并它们来避免。我已经玩弄了从文件中删除所有var DEBUG
定义并在执行之前将其注入源或extern的想法,但我遇到了两个问题:
DEBUG
会在浏览器中引发引用错误。理想的选择是测试window.DEBUG
,它不会引发参考错误。不幸的是,虽然注入/** @const */ var window = {}; /** @const */ window.DEBUG = false;
在顶层工作,减少if (window.DEBUG) {}
,但如果放在函数中,优化实际上会被恢复。
除非另一个编译器选项有效,否则唯一有意义的选择是使用window.DEBUG
并在编译之前注入/** @const */ var DEBUG = false;
并使用/\bwindow.DEBUG\b/
进行全局替换DEBUG
}。还有更好的方法吗?
答案 0 :(得分:3)
编译器的自定义构建允许您执行此操作。你基本上想要“内联常量变量”:
options.setInlineConstantVars(真);
您可以在applySafeCompilationOptions中添加它: http://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/javascript/jscomp/CompilationLevel.java?r=706
或者您可以使用Java API并添加选项(无需修改编译器的代码)。 Michael Bolin在这里给出了一个如何做到这一点的例子:
http://blog.bolinfest.com/2009/11/calling-closure-compiler-from-java.html
答案 1 :(得分:3)
使用@define注释:
@define {boolean}
DEBUG = true;
使用选项
进行编译- 限定= “DEBUG =假”
答案 2 :(得分:2)
这是一个陈旧的答案,但我发现了一种在这里没有提到的方法。
(function(){
var DEBUG = true;
if (DEBUG) {
if (something === "wrong") {
console.warn("Stop! Hammer time!");
}
else if (something === "as expected") {
console.log("All good :-)");
}
}
foo();
})();
使用ADVANCED_OPTIMIZATIONS,可以编译:
"wrong" === something ?
console.warn("Stop! Hammer time!") :
"as expected" === something && console.log("All good :-)");
foo();
在我们的构建脚本中,我们可以重写DEBUG行,将其设置为false
,然后产生此输出。
foo();
发生这种情况的原因是Closure将删除无法访问的代码。通过创建闭包并定义局部变量,Closure可以看到我们不能执行window.DEBUG === true
之类的操作,因此保证代码永远不会运行。
答案 3 :(得分:1)
您的DEBUG
变量目前是全局的。 GCC不会在简单优化模式下删除或重命名全局变量,因此它们仍然可用于可能想要访问它们的其他脚本中的任何代码。尝试将代码封装到匿名函数中。
答案 4 :(得分:1)
我解决了“使用SIMPLE_OPTIMIZATION从关闭编译的javascript中删除调试函数”的问题的方法是结合@John提出的类似方法以及使用一些@Brian Nichols更新。我只能让编译器通过放置这是我的主js文件的全局范围并进行自定义编译来删除行(使用多个.js文件,这仍然删除它们)
/** @const
* @type {boolean}
*/
var DEBUG = false;
//and used this format for my debug function
DEBUG && myLog('foo');
然后使用ant编译closure-compiler java以包含此选项options.setInlineVariables(CompilerOptions.Reach.ALL); 在@john建议的CompilationLevel.java文件中的applySafeCompilationOptions函数下。这对我有用,并没有像ADVANCED那样打破我的代码库...
答案 5 :(得分:0)
从您的代码中移除var DEBUG = true;
,并将检查if (DEBUG)
的所有条件转换为if (goog.DEBUG)
。修改编译器选项以读取--define goog.DEBUG=false
。 goog
变量内置于Closure Library API中,为编译器提供选项和标志。