有没有办法告诉 Google Closure Compiler *NOT* 内联我的本地函数? [英] Is there a way to tell Google Closure Compiler to *NOT* inline my local functions?

查看:24
本文介绍了有没有办法告诉 Google Closure Compiler *NOT* 内联我的本地函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我要找的:

  • 我想在仅禁用一项特定功能(禁用内联本地函数)的同时使用 SIMPLE 模式缩小的精彩功能.


  • 更新:答案是否定的,鉴于我的设置,这是不可能的.但对我来说,有一个解决方法,因为我正在使用 Grails.
  • 正如@Chad 在下面解释的那样,这违反了编译器的核心假设".有关详细信息,请参阅下面的 UPDATE3.
  • UPDATE: The answer is NO, it's not possible given my setup. But for me there is a workaround given I am using Grails.
  • As @Chad has explained below, "This violates core assumptions of the compiler". See my UPDATE3 below for more info.


问题形式:

  • 我正在使用 CompilationLevel.SIMPLE_OPTIMIZATIONS,它可以完成我想要的一切,除了它内联了我的本地函数.
  • 有什么办法可以解决这个问题吗?例如,是否可以在我的 JS 文件中放置一个设置来告诉 Google Closure 不要内联我的本地函数?
  • I'm using CompilationLevel.SIMPLE_OPTIMIZATIONS which does everything I want, except that it's inlining my local functions.
  • Is there any way around this? For example, is there a setting I can place in my JS files to tell Google Closure not to inline my local functions?

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

It would be cool to have some directives at the top of my javascript file such as:

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

我正在开发 Grails 应用程序并使用 Grails asset-pipeline 插件,它使用 Google Closure Compiler(以下简称 Compiler).该插件支持编译器通过 Grails 配置 grails 支持的不同缩小级别.assets.minifyOptions.这允许SIMPLE"、ADVANCED"、WHITESPACE_ONLY".

I'm developing a Grails app and using the Grails asset-pipeline plugin, which uses Google Closure Compiler (hereafter, Compiler). The plugin supports the different minification levels that Compiler supports via the Grails config grails.assets.minifyOptions. This allows for 'SIMPLE', 'ADVANCED', 'WHITESPACE_ONLY'.

AssetCompiler.groovy(资产管道插件)调用 ClosureCompilerProcessor.process()

AssetCompiler.groovy (asset-pipeline plugin) calls ClosureCompilerProcessor.process()

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

That eventually assigns SIMPLE_OPTIMIZATIONS on the CompilerOptions object. And by doing so, CompilerOptions.inlineLocalFunctions = true as a byproduct (this is hard coded behavior in Compiler). If I were to use WHITESPACE_ONLY the result would be inlineLocalFunctions=false.

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

So by using Asset Pipeline's 'SIMPLE' setting, local functions are being inlined and that is causing me trouble. Example: ExtJS ext-all-debug.js which uses lots of local functions.

SO post 是否有可能使 Google Closure 编译器*不*内联某些函数? 提供了一些帮助.我可以使用它的 window['dontBlowMeAway'] = dontBlowMeAway 技巧来防止我的函数内联.但是我有很多功能,我不会为每个功能手动执行此操作;我也不想写一个脚本来为我做这件事.创建 JS 模型并尝试识别本地函数听起来既不安全、有趣也不快速.

SO post Is it possible to make Google Closure compiler *not* inline certain functions? provides some help. I can use its window['dontBlowMeAway'] = dontBlowMeAway trick to keep my functions from inlining. However I have LOTS of functions and I'm not about to manually do this for each one; nor would I want to write a script to do it for me. Creating a JS model and trying to identity local functions doesn't sound safe, fun nor fast.

之前的 SO 帖子将读者引导至 https://developers.google.com/closure/compiler/docs/api-tutorial3#removal,其中解释了 window['bla'] 技巧,并且它有效.

The previous SO post directs the reader to https://developers.google.com/closure/compiler/docs/api-tutorial3#removal, where the window['bla'] trick is explained, and it works.

哇,感谢您阅读这么长的内容.

Wow thanks for reading this long.

帮助?:-)

更新 1:

好的.在花费所有精力写这个问题的同时,我可能有一个可行的技巧.Grails 使用 Groovy.Groovy 使用其 MetaClass API 使方法调用拦截变得容易.

Okay. While spending all the effort in writing this question, I may have a trick that could work. Grails uses Groovy. Groovy makes method call interception easy using its MetaClass API.

我将尝试拦截对以下内容的调用:

I'm going to try intercepting the call to:

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

该睡觉了,所以我稍后必须尝试.即便如此,不用黑客来解决这个问题也很好.

It's bed time so I'll have to try this later. Even so, it would be nice to solve this without a hack.


更新 2:类似帖子中的响应(是是否可以让 Google Closure 编译器*不*内联某些函数?)并没有解决我的问题,因为我需要内联大量函数.这一点我已经解释过了.

UPDATE2: The response in a similar post (Is it possible to make Google Closure compiler *not* inline certain functions?) doesn't resolve my problem because of the large quantity of functions I need inlined. I've already explained this point.

以我上面引用的 ExtJS 文件为例说明为什么上面的 类似的 SO 帖子 不能解决我的问题.查看 ext-all-debug 的原始代码.js.找到 byAttribute() 函数.然后继续查找字符串byAttribute",您将看到它是正在定义的字符串的一部分.我不熟悉这段代码,但我假设 byAttribute 的这些基于字符串的值稍后会被传递给 JS 的 eval() 函数执行.当 byAttribute 是字符串的一部分时,编译器不会改变它的这些值.一旦 function byAttribute 被内联,就无法再尝试调用该函数.

Take the ExtJS file I cited above as an example of why the above similar SO post doesn't resolve my problem. Look at the raw code for ext-all-debug.js. Find the byAttribute() function. Then keep looking for the string "byAttribute" and you'll see that it is part of strings that are being defined. I am not familiar with this code, but I'm supposing that these string-based values of byAttribute are later being passed to JS's eval() function for execution. Compiler does not alter these values of byAttribute when it's part of a string. Once function byAttribute is inlined, attempts to call the function is no longer possible.


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

UPDATE3: I attempted two strategies to resolve this problem and both proved unsuccessful. However, I successfully implemented a workaround. My failed attempts:

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

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

Method interception doesn't work because Compiler.compile() is a Java class which is invoked by a Groovy class marked as @CompileStatic. That means Groovy's MOP is not used when process() calls Google's Compiler.compile(). Even ClosureCompilerProcessor.translateMinifyOptions() (Groovy code) can't be intercepted because the class is @CompileStatic. The only method that can be intercepted is ClosureCompilerProcessor.process().

分叉 Google 的closure-compiler.jar 是我最后的丑陋手段.但就像下面@Chad 所说的那样,简单地在正确的位置插入 options.setInlineFunctions(Reach.NONE) 并没有恢复我的内联 JS 函数名称.我尝试切换其他选项,例如 setRemoveDeadCode=false 无济于事.我意识到查德说的是对的.我最终会翻转设置并可能破坏缩小的工作方式.

Forking Google's closure-compiler.jar was my last ugly resort. But just like @Chad said below, simply inserting options.setInlineFunctions(Reach.NONE) in the right place didn't resurrect my inline JS functions names. I tried toggling other options such as setRemoveDeadCode=false to no avail. I realized what Chad said was right. I would end up flipping settings around and probably destroying how the minification works.

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

My solution: I pre-compressed ext-all-debug.js with UglifyJS and added them to my project. I could have named the files ext-all-debug.min.js to do it more cleanly but I didn't. Below are the settings I placed in my 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




Keywords: minify, minification, uglify, UglifyJS, UglifyJS2

推荐答案

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

In this case, you would either need to make a custom build of the compiler or use the Java API.

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

However - disabling inlining is not enough to make this safe. Renaming and dead code elimination will also cause problems. This violates core assumptions of the compiler. This local function is ONLY referenced from within strings.

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

This code is only safe for the WHITESPACE_ONLY mode of the compiler.

这篇关于有没有办法告诉 Google Closure Compiler *NOT* 内联我的本地函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆