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。謝謝乍得=) –

相關問題