2017-10-05 46 views
3

使用UglifyJS時,除非keep_fnames設置爲true,否則函數名稱會發生​​損壞。例如,下面的代碼打字原稿:UglifyJS - Mangle函數但保留Function.prototype.name

class Test {} 
console.log(Test.name); 

編譯爲JS爲:

function Test() {} 
console.log(Test.name); 

將變醜到:

function t() {} 
console.log(t.name); 

和輸出t代替test到控制檯。

有沒有一種方法(other than using keep_fnames option)在uglification之後保留name屬性? (我不想用keep_fnames:true因爲它增加了集束大小相當多

可能的解決方案我想到:

  • 編寫的WebPack插件硬編碼函數名Test.name = 'Test',但這韓元作爲Function.prototype.name是隻讀屬性;
  • 使用Typescript裝飾器,元數據和反射API,但design:type元數據不是爲類發射的,它只是爲屬性發射(我相信是因爲Function.prototype.name存在,但我猜他們錯過了這個邊緣情況?)。
+1

你可以編寫一個Webpack插件,用''Test「替換'Test.name'的實例嗎?類似於「DefinePlugin」的功能。 – CodingIntrigue

+0

我想是的,但在這種情況下,我簡化了這個例子。在我真正的用例中,'.name'屬性是從作爲私有npm包編寫的外部庫中訪問的。 – user5365075

+0

可能的重複https://stackoverflow.com/questions/46561116/angular4-component-name-doesnt-work-on-production – estus

回答

2

由於解釋爲here,Function.prototype.name不能依賴於客戶端代碼,因爲關於函數原始名稱的信息將被縮小過程銷燬。防止它被重命名是快速和骯髒的修復。

name是隻讀的,不可配置在某些瀏覽器,這樣做類似

class Test { 
    static get name() { 
    return 'Test'; 
    } 
} 

function Test() {} 
Object.defineProperty(Test, 'name', { configurable: true, value: 'Test' }); 

將修復它在大多數瀏覽器,但導致其他不起眼的兼容性問題(例如,Android 4.x瀏覽器)。

這樣做的正確方法是從不依賴name在客戶端代碼中進行調試。至於Node.js和Electron,它取決於代碼是否需要被模糊處理。

如果字符串標識符應該存在於類或函數中,則可以選擇另一個靜態屬性名稱,例如, id或不支持但傳統的displayName

+0

很好的答案,誠實。我喜歡使用'displayName'的想法。太糟糕了,這是一個不可避免的解決方法。 – user5365075

+0

不客氣。不可避免的,是的。注意'name'的情況與'design:type'的道具不同。道具有固定的名字(它們也可以被縮小器所破壞,但這種情況幾乎不可取)。函數不。 – estus

2

有沒有一種方法(不是使用keep_fnames選項等)保存後醜化name屬性...

保持正確名稱的唯一機制涉及該名稱在輸出文件是,所以簡短的回答是否定的。如果你想使用prototype.name你需要保留這個名字。

的替代品將包括兩種:

  1. 添加包含名稱,這可能會引入錯誤,並會仍然佔用空間在文件
  2. 尋找一種工具,將預編譯所有使用附加的屬性prototype.name與字符串值...我不知道存在,但你永遠不知道!
+0

選項2我非常喜歡:)我猜寫這樣一個webpack插件是可行的,但我擔心這在這種情況下不起作用,因爲我使用函數名稱的代碼包含在外部庫中。因此,'.name'是在外部庫中訪問的。 – user5365075

+1

解決某些用途非常困難,當然,如果在多種情況下使用情況會有所不同(這可能是這種情況,否則您不會查看該值),這可能是不可能的。 – Fenton