Google Closure Compiler进阶:编译时删除代码块

发布于 2024-10-01 15:29:06 字数 365 浏览 1 评论 0原文

如果我获取此代码并编译它(高级优化),

/**@constructor*/
function MyObject() {
    this.test = 4
    this.toString = function () {return 'test object'}
}
window['MyObject'] = MyObject

我会得到此代码

window.MyObject=function(){this.test=4;this.toString=function(){return"test object"}};

有什么方法可以使用闭包编译器删除 toString 函数吗?

If I take this code and compile it (advanced optimizations)

/**@constructor*/
function MyObject() {
    this.test = 4
    this.toString = function () {return 'test object'}
}
window['MyObject'] = MyObject

I get this code

window.MyObject=function(){this.test=4;this.toString=function(){return"test object"}};

Is there any way I can remove the toString function using the Closure Compiler?

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

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

发布评论

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

评论(3

无声情话 2024-10-08 15:29:06

toString 是隐式可调用的,因此除非闭包编译器能够证明 MyObject 的结果永远不会被强制转换为字符串,否则它必须保留它。

您始终可以将其标记为显式调试代码:

this.test = 4;
if (goog.DEBUG) {
  this.toString = function () { return "test object"; };
}

然后在非调试版本中,使用

goog.DEBUG = false;

See http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.source.html 这样做

/**
 * @define {boolean} DEBUG is provided as a convenience so that debugging code
 * that should not be included in a production js_binary can be easily stripped
 * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most
 * toString() methods should be declared inside an "if (goog.DEBUG)" conditional
 * because they are generally used for debugging purposes and it is difficult
 * for the JSCompiler to statically determine whether they are used.
 */
goog.DEBUG = true;

toString is implicitly callable, so unless the Closure compiler can prove that the result of MyObject is never coerced to a string it has to preserve it.

You can always mark it as explicit debug code:

this.test = 4;
if (goog.DEBUG) {
  this.toString = function () { return "test object"; };
}

then in your non-debug build, compile with

goog.DEBUG = false;

See http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.source.html which does

/**
 * @define {boolean} DEBUG is provided as a convenience so that debugging code
 * that should not be included in a production js_binary can be easily stripped
 * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most
 * toString() methods should be declared inside an "if (goog.DEBUG)" conditional
 * because they are generally used for debugging purposes and it is difficult
 * for the JSCompiler to statically determine whether they are used.
 */
goog.DEBUG = true;
动次打次papapa 2024-10-08 15:29:06

答案非常简单。我正在研究这个问题,但没有找到正确的答案,所以我在这里添加它。解决方案是使用 JSDoc 注释(请参阅 https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#const-const-type):

/* @const */
const debug = false;

现在在代码中的任何位置(也在嵌套函数内部)您可以执行以下操作:

if (debug) console.log("hello world");

或者在您的情况下使整个块无效

if (debug) {
    /* your code to remove */    
}

如果您将 debug 设置为 false,则闭包编译器可以将其删除,因为它知道您声明了 debug 常量 a 因此如果使用调试变量进行门控,它不会改变,并且代码将永远不会被执行。

The answer is surprising simple. I was researching this and didn't find the correct answer, so I am adding it here. The solution is to use a JSDoc annotation (see https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#const-const-type):

/* @const */
const debug = false;

Now anywhere in your code (also inside of nested functions) you can do the following:

if (debug) console.log("hello world");

Or in your case invalidate a complete block

if (debug) {
    /* your code to remove */    
}

If you set debug to false the Closure compiler can remove it because it knows you declared debug a constant a hence it won't change and the code will never be executed if gated with your debug variable.

撕心裂肺的伤痛 2024-10-08 15:29:06

因为@define在模块中不起作用,所以我编写了一个可以在编译之前运行的补丁。它是:

import { c } from '@artdeco/erte'
import { readFileSync, writeFileSync } from 'fs'
import { join } from 'path'

const [,,version] = process.argv

const PATH = join(__dirname, 'index.js')
let f = readFileSync(PATH, 'utf-8')

const isFree = version == '--free'

if (isFree) {
  f = f.replace("\nimport isFree from './paid'", "\n// import isFree from './paid'")
  f = f.replace("\n// import isFree from './free'", "\nimport isFree from './free'")
  console.log('Set version to %s', c('free', 'red'))
} else {
  f = f.replace("\n// import isFree from './paid'", "\nimport isFree from './paid'")
  f = f.replace("\nimport isFree from './free'", "\n// import isFree from './free'")
  console.log('Set version to %s', c('paid', 'magenta'))
}

writeFileSync(PATH, f)

用法:
节点 ./src/version/patch --free
node ./src/version/patch --paid

以及正在修补的实际 ./src/version/index.js

// import isFree from './free'
import isFree from './paid'

使用 './free':

export default true

使用 './paid':

export default true

并基于对此,您可以从 index.js 导出一个变量:

export const free = isFree

因此,这是为了允许编译付费和免费包,但您可以扩展此代码以调整调试/生产版本。

尽管如此,这应该用 -D (@define) 来完成,但显然对于谷歌这样一家市值数万亿美元的公司来说这是非常困难的。

Because the @define doesn't work in modules, I wrote a patch that can be run before compilation. It goes:

import { c } from '@artdeco/erte'
import { readFileSync, writeFileSync } from 'fs'
import { join } from 'path'

const [,,version] = process.argv

const PATH = join(__dirname, 'index.js')
let f = readFileSync(PATH, 'utf-8')

const isFree = version == '--free'

if (isFree) {
  f = f.replace("\nimport isFree from './paid'", "\n// import isFree from './paid'")
  f = f.replace("\n// import isFree from './free'", "\nimport isFree from './free'")
  console.log('Set version to %s', c('free', 'red'))
} else {
  f = f.replace("\n// import isFree from './paid'", "\nimport isFree from './paid'")
  f = f.replace("\nimport isFree from './free'", "\n// import isFree from './free'")
  console.log('Set version to %s', c('paid', 'magenta'))
}

writeFileSync(PATH, f)

Usage:
node ./src/version/patch --free
node ./src/version/patch --paid

And the actual ./src/version/index.js that's being patched:

// import isFree from './free'
import isFree from './paid'

With './free':

export default true

With './paid':

export default true

And based on that, you can export a variable from index.js:

export const free = isFree

So this was to allow compiling paid and free packages, but you could extend this code to adjust for debug/production version.

Still, this should be done with -D (@define) but apparently it's very difficult for a trillion-dollar company that Google is.

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