防止 Closure Compiler 在不使用括号符号的情况下重命名属性

Prevent Closure Compiler from renaming properties without using bracket notation

我正在开发一款需要有条件地向最终用户公开 API 的产品。我们正在使用 Closure Compiler 进行缩小。我试图公开的 API 部分是一个函数,该函数使用 Result 调用回调,其值是具有某些属性的对象。

具体来说,我尝试公开的函数如下所示(采用伪 jsdoc 表示法):

/**
 * @type DocumentRenderResult {status: String, image?: HTMLImageElement|HTMLCanvasElement}
 * @param {function(Result<DocumentRenderResult>)} callback
**/
function renderDocument (url, page, callback) {

}

Result class 看起来像这样:

/**
 * @template T
 * @param {Boolean} ok
 * @param {T} val
 * @param {Error} err
**/
function Result (ok, val, err) {
    this.ok = ok;
    this.val = val;
    this.err = err;
}

我想要公开 Result 对象 API - 也就是说,存在 okvalerr 属性,并公开 renderDocument 接口,以便提供回调的用户将能够访问 statusimage 属性。

一个解决方案(可能)是在任何地方都使用括号表示法,但由于这应该只是有条件地公开(对于某些最终用户),我想分开是否从代码中缩小的概念。

我认为 @implements 和 @export 以及外部文件的某种组合可以实现这一点,但我还没有弄明白。

我想做的事情可行吗?

有两种主要方法可以处理这种情况:

没有闭包库

将所有导出存储在一个单独的文件中,该文件成为 api 公开库的主要入口点。此方法不依赖于外部库。有关此示例,请参阅我的 GeolocationMarker library.

使用 Closure-Library(或至少它的一部分)

如果您愿意在您的项目中使用非常小的一部分闭包库代码,您可以使用 @export 注释。 @export 除非指定编译标志 --generate_exports,否则注释不执行任何操作。

当使用 --generate_exports 时,编译器将添加对闭包库的 goog.exportProperty 或 goog.exportSymbol 方法的适当调用。

/** @const */
var mynamespace = {};

/** @export */
mynamespace.maybeExposedMethod = function() {};

使用--generate_exports标志,编译器将生成代码:

var mynamespace = {maybeExposedMethod:function() {}};
goog.exportSymbol("mynamespace.maybeExposedMethod",
    mynamespace.maybeExposedMethod);

不必依赖所有的闭包库。您可以将这两种方法的定义复制到您的源代码中。所需要的只是它们以这些名称存在。

有条件地重命名记录类型

return 匿名对象的函数必须区别对待以防止重命名。这里最好的选择是在它自己的文件中定义一个记录类型。对于要阻止重命名的 public api,将记录定义包含在外部。当您希望重命名记录属性时,将定义作为源包含在内。

my_typedefs.js

/** @typedef {{image: string, status: number}} */
var my_record_type;

my_method_def.js

/** @return {my_record_type} */
function my_method() {
  return {
    image: 'some_image.jpg',
    status: 200
  };
}

如果 my_typedefs.js 包含在带有 --js 标志的编译中,记录属性将被重命名,但如果它包含在 --externs 标志中,则不会被重命名重命名。