如何在闭包编译器中排除对象重命名

How to exclude an object from renaming in closure-compiler

我使用 closure-util 并希望有一个对象不重命名以更改 html 中的内容。
在我的第一步中,我想将我的模块与 openlayers 3|4..
一起编译 我不熟悉 externs、export 或 api ,所以我需要帮助声明闭包编译器。

片段.html(未编译)

  olc.lon=7.11875;olc.lat=51.15345;olc.zoom=12;

main.js 中的片段声明将被编译

var olc = {      // namespace controls and constants
  lon         :  2.0,lat: 25.0,rota: 0,zoom: 2, // as default
  debug       :  'force'
};
window['olc'] = olc;

现在编译后
- olc.lon 重命名为 olc.B,
- olc.lat 重命名为 olc.uj、
- olc.rota 重命名为 olc.mf、
- olc.zoom 没有重命名,我不知道为什么不和
- olc.debug 未重命名。

有zoom之类的受保护词吗?
例如,如何保护 olc.lon 不被重命名?

是的,有受保护的词,包括任何现有的全局变量(意味着 window 对象的任何 属性)和 JavaScript 关键字,可能还有更多。还有标准 "externs" 中默认包含的任何内容。我需要更多地研究为什么 zoomdebug 没有特别重命名,但它可能是这些类别之一。

有几种方法可以防止在闭包编译器中重命名(搜索该短语可能会提出更多建议)。一种快速的方法是将 属性 名称放在引号中,如下所示:

var olc = {
  'lon': 2.0,
  'lat': 25.0,
  'rota': 0,
  zoom: 2,
  debug:'force'
};
window['olc'] = olc;

看到的是example of the online closure compiler on the above code.

您也可以定义自己的 "externs" 以防止属性被重命名。请参阅有关 Advanced Compilation and Externs.

的文档

避免闭包类型系统

如果您正在使用对象字面量并且不想添加任何类型信息,您可以'quote' 属性 名称。这会导致它们的值被直接使用,并防止它们被用作推断类型的一部分(可能是 optimized/replaced,如您所见)。

// namespace controls and constants
var olc = {
  'lon'  : 2.0,
  'lat'  : 25.0,
  'rota' : 0,
  'zoom' : 2, // as default
  'debug': 'force'
};

此优化是在 per-target/project 级别执行的,而不是针对每个函数执行的,因此未替换 zoomdebug 的原因可能与 where/how 他们和其他 属性 名称在程序的其他地方使用。 你不应该依赖于此,它可能会发生不可预测的变化。 如果你需要 zoom 保持原样,你必须 quote/protect 照原样 latlon.

使用闭包类型系统

Closure 类型系统可能非常有用,像这样避免它会阻止它检测这些值的一些潜在错误。相反,你可以在 Closure 的系统中给 object/value 一个类型,它将进行错误检查,但知道不重命名。

遗憾的是,有很多方法可以做到这一点,其中很多都依赖于 Closure Compiler 设置的微妙组合。 (文档可能会告诉您使用 @exports,但在某些情况下即使这些也不起作用。)这是我最常使用的解决方案,因为它适用于大多数设置并且在概念上易于理解:使用您需要保留的属性定义一个外部接口,并将其应用于您的对象。

您可以在 "externs file" 中定义此接口类型,如果您使用的是命令行,则可以使用 --externs 标志将其包含在构建中(请参阅 "Declaring Externs" in the documentation ).

/externs.js
/** @interface */
function ControlsAndConstants() {}
/** @type {number} */
ControlsAndConstants.prototype.lat;
/** @type {number} */
ControlsAndConstants.prototype.lon;
/** @type {number} */
ControlsAndConstants.prototype.rota;
/** @type {number} */
ControlsAndConstants.prototype.zoom;
/** @type {*} */
ControlsAndConstants.prototype.debug;
/main.js
// namespace controls and constants
var olc = /** @type {ControlsAndConstants} */ ({
  lon  : 2.0,
  lat  : 25.0,
  rota : 0,
  zoom : 2, // as default
  debug: 'force'
});

window['olc'] = olc;

请注意,属性 名称不再被引用。我们现在希望 Closure 能够理解它们,而不是忽略它们。

为什么这行得通? externs 文件告诉 Closure "This ControlsAndConstants interface already exists and is being used by code you don't compile. Because you can't optimize that code to rename the properties, you need to use the same property names yourself for compatibility." 足够简单!