javascript - 有没有办法告诉Google Closure Compiler *不要*内联我的本地函数?

标签 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支持的不同缩小级别。这允许“SIMPLE”,“ADVANCED”,“WHITESPACE_ONLY”。

    AssetCompiler.groovy( Assets 管道插件)调用ClosureCompilerProcessor.process()
    最终,在CompilerOptions对象上分配了SIMPLE_OPTIMIZATIONS。通过这样做,CompilerOptions.inlineLocalFunctions = true作为副产品(这是Compiler中的硬编码行为)。如果我使用WHITESPACE_ONLY,结果将是inlineLocalFunctions=false

    因此,通过使用Asset Pipeline的“SIMPLE”设置,内联了本地函数,这给我带来了麻烦。示例:ExtJS ext-all-debug.js使用很多本地函数。

    所以Is it possible to make Google Closure compiler *not* inline certain functions? post提供了一些帮助。我可以使用其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:我尝试了两种策略来解决此问题,但均未成功。但是,我成功实现了一种解决方法。我失败的尝试:
  • 使用Groovy方法拦截(元对象协议(protocol),又称MOP)来拦截com.google.javascript.jscomp.Compiler.compile()
  • fork closure-compiler.jar(创建我自己的自定义副本),并通过设置com.google.javascript.jscomp.applySafeCompilationOptions()而不是LOCAL来修改options.setInlineFunctions(Reach.NONE);

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

    fork 谷歌的closures-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'
    ]
    

    做完了问题解决了。


    关键字:缩小,缩小,uglify,UglifyJS,UglifyJS2

    最佳答案

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

    但是-禁用内联不足以使其安全。重命名和无效代码删除也会引起问题。这违反了编译器的核心假设。仅在字符串内引用此局部函数。

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

    关于javascript - 有没有办法告诉Google Closure Compiler *不要*内联我的本地函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36929970/

    相关文章:

    javascript - window.onbeforeunload 不会立即触发

    javascript - 使用 Webpack 将 TypeScript 转为 es5

    javascript - 在每个函数内处理 "that"时出现奇怪的 JS 行为

    grails - 静态映射关闭中的Grails “duplicate field name”错误

    javascript - Onclick 上的 href 链接文件未在 Android 移动网络应用程序中下载

    mysql - 将 grails/groovy 枚举映射到 Mysql 枚举

    Grails: getClass().getResource ("whatever") 不起作用

    grails - 在 Cloudbees 上运行 LDAP 服务器

    grails - Crawler4j计算页面深度

    unit-testing - 使用 Groovy AST 转换时的代码覆盖率指标