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

发布于 2024-09-03 13:43:38 字数 898 浏览 8 评论 0原文

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

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

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

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

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

  1. 使用分号是标准技术,还是有其他方法吗?

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

  3. 其他解决方案是否也可以适应这种方式工作,或者它们是否有替代方法来实现此目的?

  4. 我最终可能会开始使用 Closure Compiler。我现在应该做些什么来为此做好准备吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

提笔落墨 2024-09-10 13:43:38

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

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

这甚至可以与 SIMPLE_OPTIMIZATIONS 一起使用,并且不需要 --define=

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 !

谁与争疯 2024-09-10 13:43:38

这是我与闭包编译器一起使用的内容。首先,您需要像这样定义一个 DEBUG 变量:

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

它使用 JS 注释进行闭包,您可以阅读有关 文档中

现在,每当您需要一些仅调试代码时,只需将其包装在 if 语句中,如下所示:

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

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

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.

等往事风中吹 2024-09-10 13:43:38

在这种情况下,一个好的解决方案可能是 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"/>

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"/>
安穩 2024-09-10 13:43:38

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

如果您已经准备为生产代码添加构建步骤,则始终可以在顶部添加另一个文件,将您的 console 方法转换为 noop 方法。

类似于:

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

理想情况下,您只需删除任何控制台方法,但如果您无论如何都保留它们但不使用它们,这可能是最容易使用的。

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.

颜漓半夏 2024-09-10 13:43:38

如果您在高级模式下使用闭包编译器,您可以执行以下操作:

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

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

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

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

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

If you use the Closure Compiler in Advanced mode, you can do something like:

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

Then the compiler will remove all your console.log calls. Of course you need to --define the variable DEBUG in the command line.

However, this is only for Advanced mode. If you are using Simple mode, you'll need to run a preprocessor on your source file.

Why not consider the Dojo Toolkit? It has built-in comment-based pragma's to include/exclude sections of code based on a build. Plus, it is compatible with the Closure Compiler in Advanced mode (see link below)!

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

将军与妓 2024-09-10 13:43:38

尽管这是一个老问题。我今天偶然发现了同样的问题,发现可以使用 编译器选项

我关注了此帖子

在将代码发送到客户端之前,我们在服务器上运行 Java 编译器。这在简单模式下对我们有用。

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...等的调用

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

掐死时间 2024-09-10 13:43:38

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

If you're using UglifyJS2, you can use the drop_console argument to remove console.* functions.

所谓喜欢 2024-09-10 13:43:38

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

if (process.env.REACT_APP_STAGE === 'PROD')
  console.log = function no_console() {};

换句话说,console.log 在产品环境中不会返回任何内容。

I use this in my React apps:

if (process.env.REACT_APP_STAGE === 'PROD')
  console.log = function no_console() {};

In other words, console.log will return nothing on prod enviroment.

雨落□心尘 2024-09-10 13:43:38

我和@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");

I am with @marcel-korpel. Isn't perfect but works. Replace the debug instructions before minification. The regular expression works in many places. Watch out unenclosed lines.

/console\.[^;]*/gm

Works on:

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

Don't works:

console.log("instruction without semicolon")
console.log("semicolon in ; string");
水波映月 2024-09-10 13:43:38

到目前为止,我还没有研究过缩小,但是可以使用简单的正则表达式来完成此行为:

s/;;;.*//g

这会将三个分号之后(并包括)的行中的所有内容替换为空,因此在缩小之前将其丢弃。您可以在运行缩小工具之前运行 sed (或类似的工具),如下所示:

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

顺便说一句,如果您想知道打包版本或缩小版本是否“更好”,请阅读 JavaScript 压缩方法的比较

I haven't looked into minification so far, but this behaviour could be accomplished using a simple regular expression:

s/;;;.*//g

This replaces everything in a line after (and including) three semicolons with nothing, so it's discarded before minifying. You can run sed (or a similar tool) before running your minification tool, like this:

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

BTW, if you're wondering whether the packed version or the minified version will be 'better', read this comparison of JavaScript compression methods.

痴骨ら 2024-09-10 13:43:38

我使用了以下自制的东西:

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

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

因此,当您声明设置为 true 的变量 debug 时 - 所有 ShowDebugMessage() 调用也会调用 alert() 。因此,只需在代码中使用它,而无需考虑 ifdef 等就地条件或调试输出行的手动注释。

I've used following self-made stuf:

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

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

So when you've declared variable debug which is set to true - all ShowDebugMessage() calls would call alert() as well. So just use it in a code and forget about in place conditions like ifdef or manual commenting of the debug output lines.

一人独醉 2024-09-10 13:43:38

我正在寻找一个内置选项来执行此操作。我还没有找到,但我的最喜欢的答案也不需要对现有源代码进行任何更改。以下是基本用法的示例。

假设 HTML 文件 test.html 具有:

<html>
        <script src="hallo.js"></script>
</html>

hallo.js 具有:

sayhi();
function sayhi()
{
        console.log("hallo, world!");
}

我们将使用一个单独的文件,例如 noconsole.js,具有以下内容来自链接的答案:

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

然后我们可以按如下方式编译它,记住顺序很重要,noconsole.js必须放在参数的前面:

google-closure-compiler --js noconsole.js hallo.js --js_output_file hallo.out.js

如果你cat Hallo.out.js< /code> 你会看到:

console.log=console.debug=console.info=function(){};sayhi();function sayhi(){console.log("hallo, world!")};

如果我使用 mv Hallo.out.js Hallo.js 进行测试并重新加载页面,我可以看到控制台现在是空的。

希望这能澄清这一点。请注意,我尚未在使用 ADVANCED 优化编译所有源代码的理想模式下对此进行测试,但我希望它也能工作。

I was searching for a built-in option to do this. I have not found that yet, but my favorite answer also does not require any changes to existing source code. Here's an example with basic usage.

Assume HTML file test.html with:

<html>
        <script src="hallo.js"></script>
</html>

And hallo.js with:

sayhi();
function sayhi()
{
        console.log("hallo, world!");
}

We'll use a separate file, say noconsole.js, having this from the linked answer:

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

Then we can compile it as follows, bearing in mind that order matters, noconsole.js must be placed first in the arguments:

google-closure-compiler --js noconsole.js hallo.js --js_output_file hallo.out.js

If you cat hallo.out.js you'd see:

console.log=console.debug=console.info=function(){};sayhi();function sayhi(){console.log("hallo, world!")};

And if I test with mv hallo.out.js hallo.js and reload the page, I can see that the console is now empty.

Hope this clarifies it. Note that I have not yet tested this in the ideal mode of compiling all the source code with ADVANCED optimizations, but I'd expect it to also work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文