0

这里就是我在寻找:有没有办法告诉Google Closure Compiler *不*内联我的本地功能?

  • 我想同时禁用只是一个特定功能(禁用本地内联函数)使用简单模式微小的奇妙的功能。


  • UPDATE:答案是NO,它给我的设置是不可能的。但是对于我来说有一个解决方法,因为我正在使用Grails。
  • 正如@Chad在下面解释的那样,“这违反了编译器的核心假设”。有关更多信息,请参阅下面的UPDATE3。



在问表:

  • 我使用CompilationLevel.SIMPLE_OPTIMIZATIONS该做的一切我想要的,只不过它内联我的本地功能。
  • 有没有办法解决这个问题?例如,是否可以在我的JS文件中放置一个设置来告诉Google Closure不要内联我的本地功能?

这将是很酷的,在我的javascript文件的顶部,如一些指令:

// This is a JS comment... 
// google.closure.compiler = [inlineLocalFunctions: false] 

我开发一个Grails应用程序,并使用Grails asset-pipeline插件,它使用谷歌关闭编译器(此后,编译器)。该插件支持编译器通过Grails config grails.assets.minifyOptions支持的不同缩小级别。这允许'简单','高级','WHITESPACE_ONLY'。

AssetCompiler.groovy(资产流水线插件)调用ClosureCompilerProcessor.process()

,最终分配SIMPLE_OPTIMIZATIONS在CompilerOptions对象。通过这样做,CompilerOptions.inlineLocalFunctions = true作为副产品(这是编译器中的硬编码行为)。如果我要使用WHITESPACE_ONLY,结果将是inlineLocalFunctions=false

因此,通过使用Asset Pipeline的'SIMPLE'设置,本地函数正在被内联,这给我带来了麻烦。例如:ExtJS ext-all-debug.js,它使用许多本地功能。

SO帖子Is it possible to make Google Closure compiler *not* inline certain functions?提供了一些帮助。我可以使用它的window['dontBlowMeAway'] = dontBlowMeAway技巧来保持我的函数不被内联。不过,我有很多功能,我不打算为每个功能手动执行此操作;我也不想写一个脚本来为我做。创建JS模型并尝试识别本地函数听起来并不安全,有趣也不快。

之前的SO帖子指示读者到https://developers.google.com/closure/compiler/docs/api-tutorial3#removal,其中window['bla']技巧被解释,它的工作原理。

感谢您阅读这篇长文。

帮助? :-)


UPDATE1:

好。在花费所有的精力写这个问题的时候,我可能会有一个可行的窍门。 Grails使用Groovy。 Groovy使用它的MetaClass API使方法调用拦截变得容易。

我要去尝试呼叫拦截到:

com.google.javascript.jscomp.Compiler.compile(
    List<T1> externs, List<T2> inputs, CompilerOptions options) 

我的拦截方法是这样的:

options.inlineLocalFunctions=false 
// Then delegate call to the real compile() method 

午睡时间到了,所以我得后来尝试。即便如此,如果不进行破解就可以解决这个问题。



UPDATE2: 在一个类似的帖子(Is it possible to make Google Closure compiler *not* inline certain functions?)的响应不能解决,因为我需要内联函数的大量的我的问题。我已经解释了这一点。

以上面引用的ExtJS文件为例说明为什么上述similar SO post无法解决我的问题。看看ext-all-debug.js的原始代码。找到byAttribute()函数。然后继续查找字符串“byAttribute”,你会发现它是正在定义的字符串的一部分。我对此代码并不熟悉,但我认为byAttribute的这些基于字符串的值稍后将传递给JS's eval()函数以供执行。当它是字符串的一部分时,编译器不会更改byAttribute的这些值。一旦function byAttribute内联,尝试调用该函数不再可能。



UPDATE3:我尝试两种策略来解决这个问题,都证明是不成功的。但是,我成功实施了一种解决方法。我的失败尝试:

  1. 使用Groovy方法拦截(元对象协议,又称MOP)拦截com.google.javascript.jscomp.Compiler.compile()
  2. 分叉closure-compiler.jar(制作我自己的自定义副本)并通过设置options.setInlineFunctions(Reach.NONE);而不是LOCAL修改com.google.javascript.jscomp.applySafeCompilationOptions()

方法拦截不起作用,因为Compiler.compile()是由Groovy类调用的Java类,标记为@CompileStatic。这意味着当process()称为Google的Compiler.compile()时,Groovy的MOP不会被使用。即使ClosureCompilerProcessor.translateMinifyOptions()(Groovy代码)也不能被拦截,因为该类是@CompileStatic。唯一可以拦截的方法是ClosureCompilerProcessor.process()

分叉Google的closure-compiler.jar是我最后一个丑陋的手段。但就像下面的@Chad所说的那样,只要在正确的位置插入options.setInlineFunctions(Reach.NONE)就不会重新生成我的内联JS函数名称。我试图切换其他选项,如setRemoveDeadCode=false无济于事。我意识到乍得说的是对的。我最终会翻转设置并可能破坏缩小的工作方式。

我的解决方案:我用UglifyJS预压缩了ext-all-debug.js并将它们添加到我的项目中。我可以命名文件ext-all-debug.min.js做得更干净,但我没有。以下是我放置在我的Grails Config.groovy中的设置:

grails.assets.minifyOptions = [ 
    optimizationLevel: 'SIMPLE' // WHITESPACE_ONLY, SIMPLE or ADVANCED 
] 

grails.assets.minifyOptions.excludes = [ 
    '**ext-all-debug.js', 
    '**ext-theme-neptune.js' 
] 

完成。问题解决了。




关键词:缩小,缩小,丑化,UglifyJS,UglifyJS2

+0

你能解释**为什么**本地函数内联会导致你的问题?有多种技术可以防止这种情况,但我需要知道提出建议的核心原因。 –

+0

[可以使Google Closure编译器\ *不是\ *内联某些函数吗?]的可能的重复?(http://stackoverflow.com/questions/4297685/is-it-possible-to-make-google-closure-编译器非内联特定函数) –

+0

谢谢@ChadKillingsworth。我已将“UPDATE2”添加到我的问题中,作为对您问题的回复。事实上,如果您阅读了我原来的问题,那么您可能会考虑“可能重复”的意见。和平兄弟。 –

回答

2

在这种情况下,你要么需要使编译器的自定义生成或使用Java API。

但是,禁用内联并不足以保证安全。重命名和无效代码消除也会导致问题。这违反了编译器的核心假设。这个本地函数只能从字符串中引用。

此代码仅对编译器的WHITESPACE_ONLY模式安全。

+0

你说得对。有关详细信息和我的成功解决方法,请参阅UPDATE3。谢谢乍得=) –