有没有办法告诉Google Closure Compiler * NOT *内联我的本地函数?

时间:2016-04-29 05:07:34

标签: javascript grails groovy asset-pipeline google-closure-compiler

以下是我要找的内容:

  • 我想使用SIMPLE模式缩小的精彩功能,同时只禁用一个特定功能(禁用本地内联功能)。


  • 更新:答案是否定的,根据我的设置,这是不可能的。但对我来说,有一个解决方法,因为我使用的是Grails。
  • 正如@Chad在下面解释的那样,"这违反了编译器的核心假设"。有关详细信息,请参阅下面的UPDATE3。


问题形式:

  • 我使用CompilationLevel.SIMPLE_OPTIMIZATIONS来完成我想要的一切,除了它内联我的本地功能。
  • 有什么方法吗?例如,我可以在JS文件中放置一个设置来告诉Google Closure不要内联我的本地函数吗?

在我的javascript文件的顶部有一些指令很酷,例如:

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

我正在开发Grails应用并使用Grails asset-pipeline插件,该插件使用Google Closure Compiler(以下称为编译器)。该插件通过Grails config grails.assets.minifyOptions支持Compiler支持的不同缩小级别。这样就可以实现“简单”,“高级”,“白痴”等。

AssetCompiler.groovy(asset-pipeline plugin)调用ClosureCompilerProcessor.process()

最终在CompilerOptions对象上分配SIMPLE_OPTIMIZATIONS。通过这样做,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()函数。然后继续寻找字符串&#34; byAttribute&#34;并且您将看到它是正在定义的字符串的一部分。我不熟悉这段代码,但我假设这些基于字符串的byAttribute值稍后被传递给JS's eval()函数执行。当编译器成为字符串的一部分时,编译器不会更改byAttribute的这些值。内联function byAttribute后,无法再尝试调用该函数。


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

  1. 使用Groovy方法拦截(元对象协议,又名MOP)拦截com.google.javascript.jscomp.Compiler.compile()
  2. fork the closure-compiler.jar(制作我自己的自定义副本)并通过设置com.google.javascript.jscomp.applySafeCompilationOptions()而不是LOCAL来修改options.setInlineFunctions(Reach.NONE);
  3. 方法拦截不起作用,因为Compiler.compile()是一个Java类,由标记为@CompileStatic的Groovy类调用。这意味着当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'
    ]
    

    完成。问题解决了。




    关键词:minify,minification,uglify,UglifyJS,UglifyJS2

2 个答案:

答案 0 :(得分:2)

在这种情况下,您需要自定义构建编译器或使用Java API。

然而 - 禁用内联不足以使其安全。重命名和死代码消除也会导致问题。这违反了编译器的核心假设。此本地函数仅在字符串中引用。

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

答案 1 :(得分:0)

使用函数构造函数

Subform1

Closure将保留String文字。

请参阅https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Function

相关问题