有没有办法告诉 Google Closure Compiler *NOT* 内联我的本地函数?
Is there a way to tell Google Closure Compiler to *NOT* inline my local functions?
这是我要找的:
- 我想使用 SIMPLE 模式缩小的美妙功能,同时禁用一个特定功能(禁用本地函数内联)。
- 更新:答案是否定的,根据我的设置这是不可能的。但对我来说有一个解决方法,因为我正在使用 Grails。
- 正如@Chad 在下面解释的那样,"This violates core assumptions of the compiler"。有关详细信息,请参阅下面的更新3。
在问题表中:
- 我正在使用
CompilationLevel.SIMPLE_OPTIMIZATIONS
,它可以做我想做的一切,除了它内联我的本地函数。
- 有什么办法解决这个问题吗?例如,是否可以在我的 JS 文件中放置一个设置来告诉 Google 闭包不要内联我的本地函数?
在我的 javascript 文件顶部添加一些指令会很酷,例如:
// This is a JS comment...
// google.closure.compiler = [inlineLocalFunctions: false]
我正在开发一个 Grails 应用程序并使用 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。这允许 'SIMPLE'、'ADVANCED'、'WHITESPACE_ONLY'.
AssetCompiler.groovy(资产管道插件)调用 ClosureCompilerProcessor.process()
最终在 CompilerOptions 对象上分配 SIMPLE_OPTIMIZATIONS
。通过这样做,CompilerOptions.inlineLocalFunctions = true
作为副产品(这是编译器中的硬编码行为)。如果我使用 WHITESPACE_ONLY
,结果将是 inlineLocalFunctions=false
。
因此,通过使用 Asset Pipeline 的 'SIMPLE' 设置,本地函数被内联,这给我带来了麻烦。示例:ExtJS ext-all-debug.js 使用大量本地函数。
SO post Is it possible to make Google Closure compiler *not* inline certain functions? 提供了一些帮助。我可以使用它的 window['dontBlowMeAway'] = dontBlowMeAway
技巧来防止我的函数内联。但是我有很多功能,我不会为每个功能手动执行此操作;我也不想写一个脚本来为我做这件事。创建 JS 模型并尝试识别本地函数听起来既不安全、有趣也不快速。
之前的 SO post 将 reader 定向到 https://developers.google.com/closure/compiler/docs/api-tutorial3#removal,其中解释了 window['bla']
技巧,并且有效。
哇,感谢阅读这么长的时间。
帮忙? :-)
更新1:
好的。在花费所有精力写这个问题的同时,我可能有一个可行的技巧。 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
现在是睡觉时间,所以我必须稍后再试。即便如此,如果不用 hack 就可以解决这个问题。
更新2:
类似 post (Is it possible to make Google Closure compiler *not* inline certain functions?) 中的响应无法解决我的问题,因为我需要内联大量函数。这点我已经解释过了。
以我上面引用的ExtJS文件为例,说明为什么要执行上面的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()函数。当 byAttribute
是字符串的一部分时,编译器不会更改这些值。一旦 function byAttribute
被内联,就不再可能尝试调用该函数。
UPDATE3: 我尝试了两种策略来解决这个问题,但都没有成功。但是,我成功地实施了一个解决方法。我失败的尝试:
- 使用Groovy方法拦截(元对象协议,又名MOP)拦截
com.google.javascript.jscomp.Compiler.compile()
.
- 分叉闭包-compiler.jar(制作我自己的自定义副本)并通过设置
options.setInlineFunctions(Reach.NONE);
而不是 LOCAL 来修改 com.google.javascript.jscomp.applySafeCompilationOptions()
。
方法拦截不起作用,因为 Compiler.compile()
是一个 Java class,它由标记为 [=30= 的 Groovy class 调用].这意味着当 process()
调用 Google 的 Compiler.compile()
时,不会使用 Groovy 的 MOP。甚至ClosureCompilerProcessor.translateMinifyOptions()
(Groovy代码)也无法被拦截,因为class是@CompileStatic
。唯一可以拦截的方法是ClosureCompilerProcessor.process()
.
分叉 Google 的闭包-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, 缩小, uglify, UglifyJS, UglifyJS2
在这种情况下,您需要自定义构建编译器或使用 Java API。
但是 - 禁用内联不足以保证安全。重命名和删除死代码也会导致问题。这违反了编译器的核心假设。此本地函数仅在字符串中引用。
此代码仅对编译器的 WHITESPACE_ONLY
模式是安全的。
使用构造函数
var fnc = new Function("param1", "param2", "alert(param1+param2);");
闭包将保留字符串文字。
见https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Function
这是我要找的:
- 我想使用 SIMPLE 模式缩小的美妙功能,同时禁用一个特定功能(禁用本地函数内联)。
- 更新:答案是否定的,根据我的设置这是不可能的。但对我来说有一个解决方法,因为我正在使用 Grails。
- 正如@Chad 在下面解释的那样,"This violates core assumptions of the compiler"。有关详细信息,请参阅下面的更新3。
在问题表中:
- 我正在使用
CompilationLevel.SIMPLE_OPTIMIZATIONS
,它可以做我想做的一切,除了它内联我的本地函数。 - 有什么办法解决这个问题吗?例如,是否可以在我的 JS 文件中放置一个设置来告诉 Google 闭包不要内联我的本地函数?
在我的 javascript 文件顶部添加一些指令会很酷,例如:
// This is a JS comment...
// google.closure.compiler = [inlineLocalFunctions: false]
我正在开发一个 Grails 应用程序并使用 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。这允许 'SIMPLE'、'ADVANCED'、'WHITESPACE_ONLY'.
AssetCompiler.groovy(资产管道插件)调用 ClosureCompilerProcessor.process()
最终在 CompilerOptions 对象上分配 SIMPLE_OPTIMIZATIONS
。通过这样做,CompilerOptions.inlineLocalFunctions = true
作为副产品(这是编译器中的硬编码行为)。如果我使用 WHITESPACE_ONLY
,结果将是 inlineLocalFunctions=false
。
因此,通过使用 Asset Pipeline 的 'SIMPLE' 设置,本地函数被内联,这给我带来了麻烦。示例:ExtJS ext-all-debug.js 使用大量本地函数。
SO post Is it possible to make Google Closure compiler *not* inline certain functions? 提供了一些帮助。我可以使用它的 window['dontBlowMeAway'] = dontBlowMeAway
技巧来防止我的函数内联。但是我有很多功能,我不会为每个功能手动执行此操作;我也不想写一个脚本来为我做这件事。创建 JS 模型并尝试识别本地函数听起来既不安全、有趣也不快速。
之前的 SO post 将 reader 定向到 https://developers.google.com/closure/compiler/docs/api-tutorial3#removal,其中解释了 window['bla']
技巧,并且有效。
哇,感谢阅读这么长的时间。
帮忙? :-)
更新1:
好的。在花费所有精力写这个问题的同时,我可能有一个可行的技巧。 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
现在是睡觉时间,所以我必须稍后再试。即便如此,如果不用 hack 就可以解决这个问题。
更新2: 类似 post (Is it possible to make Google Closure compiler *not* inline certain functions?) 中的响应无法解决我的问题,因为我需要内联大量函数。这点我已经解释过了。
以我上面引用的ExtJS文件为例,说明为什么要执行上面的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()函数。当 byAttribute
是字符串的一部分时,编译器不会更改这些值。一旦 function byAttribute
被内联,就不再可能尝试调用该函数。
UPDATE3: 我尝试了两种策略来解决这个问题,但都没有成功。但是,我成功地实施了一个解决方法。我失败的尝试:
- 使用Groovy方法拦截(元对象协议,又名MOP)拦截
com.google.javascript.jscomp.Compiler.compile()
. - 分叉闭包-compiler.jar(制作我自己的自定义副本)并通过设置
options.setInlineFunctions(Reach.NONE);
而不是 LOCAL 来修改com.google.javascript.jscomp.applySafeCompilationOptions()
。
方法拦截不起作用,因为 Compiler.compile()
是一个 Java class,它由标记为 [=30= 的 Groovy class 调用].这意味着当 process()
调用 Google 的 Compiler.compile()
时,不会使用 Groovy 的 MOP。甚至ClosureCompilerProcessor.translateMinifyOptions()
(Groovy代码)也无法被拦截,因为class是@CompileStatic
。唯一可以拦截的方法是ClosureCompilerProcessor.process()
.
分叉 Google 的闭包-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, 缩小, uglify, UglifyJS, UglifyJS2
在这种情况下,您需要自定义构建编译器或使用 Java API。
但是 - 禁用内联不足以保证安全。重命名和删除死代码也会导致问题。这违反了编译器的核心假设。此本地函数仅在字符串中引用。
此代码仅对编译器的 WHITESPACE_ONLY
模式是安全的。
使用构造函数
var fnc = new Function("param1", "param2", "alert(param1+param2);");
闭包将保留字符串文字。
见https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Function