防止 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 - 也就是说,存在 ok
、val
和 err
属性,并公开 renderDocument
接口,以便提供回调的用户将能够访问 status
和 image
属性。
一个解决方案(可能)是在任何地方都使用括号表示法,但由于这应该只是有条件地公开(对于某些最终用户),我想分开是否从代码中缩小的概念。
我认为 @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
标志中,则不会被重命名重命名。
我正在开发一款需要有条件地向最终用户公开 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 - 也就是说,存在 ok
、val
和 err
属性,并公开 renderDocument
接口,以便提供回调的用户将能够访问 status
和 image
属性。
一个解决方案(可能)是在任何地方都使用括号表示法,但由于这应该只是有条件地公开(对于某些最终用户),我想分开是否从代码中缩小的概念。
我认为 @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
标志中,则不会被重命名重命名。