简体   繁体   English

具有Closure Compiler和ADVANCED_OPTIMIZATIONS的模块模式

[英]Module pattern with Closure Compiler and ADVANCED_OPTIMIZATIONS

I am aware that similar questions have been asked before, but methodology changes quickly so I'm seeking to understand current best practices. 我知道之前已经提出了类似的问题,但方法很快就会发生变化,因此我正在寻求了解当前的最佳实践。 (In fact, as recently as 2 days ago, Chad Killingsworth added a comment to an accepted answer from three years ago that @expose annotation is now deprecated.) (事实上​​,就在2天前,Chad Killingsworth对三年前接受的答案添加了评论,即@expose注释现已弃用。)

I'm using the module pattern . 我正在使用模块模式 Working JSFIDDLE of the below code: 使用以下代码的JSFIDDLE

/** @const */
var MATHCALCS = (function () {
    'use strict';

    var MY = {};

    /**
     * @constructor
     * @param {!Object} obj
     * @expose
     */
    MY.ModuleStruct = function (obj) {
        /** @expose */
        this.color = (obj.color !== undefined) ? obj.color : null;
        /** @expose */
        this.size = (obj.size !== undefined) ? obj.size : null;
    };

    /**
     * @expose
     */
    MY.ModuleStruct.prototype.clone = function () {
        return new MY.ModuleStruct({
            "color": this.color,
                "size": this.size
        });
    };


    MY.moduleProperty = 1;

    /**
     * @type {function(!Array<number>)}
     * @expose
     */
    MY.moduleMethod = function (a) {
        var i, x = 0;
        for (i = 0; i < a.length; i += 1) {
            x = x + a[i];
        }
        return x;
    };

    return MY;

}());

window["MATHCALCS"] = MATHCALCS;*

Currently, using @expose annotation, above can be minified with Closure in advance mode and the following calls work ( minified example ): 目前,使用@expose注释,可以使用Closure in advance模式缩小上面的内容,并且以下调用可以工作( 缩小示例 ):

// call a public method
alert(MATHCALCS.moduleMethod([1, 2, 3]));

// allocate a new structure
var ms = new MATHCALCS.ModuleStruct({
    "color": "red",
        "size": "small"
});
alert(ms.color + '\t' + ms.size);

// clone a second instance
var ms2 = ms.clone();
alert(ms2.color + '\t' + ms2.size);
alert(ms !== ms2); // cloned objs are not equal

// and directly update the properties of the object
ms2.color = "white";
ms2.size = "large";
alert(ms2.color + '\t' + ms2.size);

If possible, without changing away from the module pattern, I would like to update code (approx 10,000 lines) to use @export annotation. 如果可能的话,在不改变模块模式的情况下,我想更新代码(大约10,000行)以使用@export注释。 However, when I replace @expose with @export Closure raises this error: 然而,当我更换@expose@export关闭引发此错误:

ERROR - @export only applies to symbols/properties defined in the global scope. 错误 - @export仅适用于全局范围中定义的符号/属性。

Q: Is it possible, and if so, how should the above code be annotated to work with ADVANCED_OPTIMIZATIONS? 问:是否可能,如果可行,上述代码应如何注释以使用ADVANCED_OPTIMIZATIONS?

I am aware that I can possibly use this type of notation: 我知道我可以使用这种表示法:

MY["ModuleStruct"] = MY.ModuleStruct;
MY["ModuleStruct"]["prototype"]["clone"] = MY.ModuleStruct.prototype.clone;

but exporting object properties this way will become tedious. 但以这种方式导出对象属性将变得乏味。 Further JSLint complains about weird assignments so I would rather use JSDocs annotation. 进一步的JSLint抱怨奇怪的任务,所以我宁愿使用JSDocs注释。

Until the issue raised by @ChadKillingsworth is resolved, here's a solution which will enable you to use @export with only minor modifications to your code: @ChadKillingsworth提出的问题得到解决之前,这里有一个解决方案,只需对代码进行少量修改即可使用@export

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

goog.scope(function () {
    'use strict';

    var MY = MATHCALCS;

    /**
     * @constructor
     * @param {!Object} obj
     * @export
     */
    MY.ModuleStruct = function (obj) {
        this.color = (obj.color !== undefined) ? obj.color : null;
        this.size = (obj.size !== undefined) ? obj.size : null;
    };

    /**
     * @export
     */
    MY.ModuleStruct.prototype.clone = function () {
        return new MY.ModuleStruct({
            "color": this.color,
                "size": this.size
        });
    };


    MY.moduleProperty = 1;

    /**
     * @type {function(!Array<number>)}
     * @export
     */
    MY.moduleMethod = function (a) {
        var i, x = 0;
        for (i = 0; i < a.length; i += 1) {
            x = x + a[i];
        }
        return x;
    };

});

The changes are: 变化是:

  • Change the @expose tags to @export . @expose标记更改为@export
  • Create an empty MATHCALCS object outside the module wrapper function, and make the MY alias point to it. 在模块包装函数外部创建一个空的MATHCALCS对象,并使MY别名指向它。
  • Instead of executing the module wrapper function immediately (IIFE), pass it to goog.scope() . 不是立即执行模块包装函数(IIFE),而是将其传递给goog.scope() This enables aliasing within scope functions, allowing the compiler to work out that the exported symbols are being defined on the global MATHCALCS object. 这样可以在范围函数中启用别名,从而允许编译器确定在全局MATHCALCS对象上定义导出的符号。 This prevents the compiler from raising the error (" @export only applies to symbols/properties defined in the global scope"). 这可以防止编译器引发错误(“ @export仅适用于在全局范围中定义的符号/属性”)。
  • Remove the following items, which are not needed: 删除以下不需要的项目:
    • The @export tags on this.color and this.size this.colorthis.size上的@export标记
    • return MY;
    • window["MATHCALCS"] = MATHCALCS;

When compiled with this command: 使用此命令编译时:

java -jar compiler.jar \
    --js closure/goog/base.js \
    --js mathcalcs.js \
    --js_output_file mathcalcs.min.js \
    --compilation_level ADVANCED_OPTIMIZATIONS \
    --generate_exports \
    --formatting PRETTY_PRINT \
    --output_wrapper '(function() {%output%}).call(window);'

you'll get: 你会得到:

(function() {var f = this;
function g(a, d) {
  var b = a.split("."), c = f;
  b[0] in c || !c.execScript || c.execScript("var " + b[0]);
  for (var e;b.length && (e = b.shift());) {
    b.length || void 0 === d ? c[e] ? c = c[e] : c = c[e] = {} : c[e] = d;
  }
}
;function h(a) {
  this.color = void 0 !== a.color ? a.color : null;
  this.size = void 0 !== a.size ? a.size : null;
}
g("MATHCALCS.ModuleStruct", h);
h.prototype.clone = function() {
  return new h({color:this.color, size:this.size});
};
h.prototype.clone = h.prototype.clone;
g("MATHCALCS.moduleMethod", function(a) {
  var d, b = 0;
  for (d = 0;d < a.length;d += 1) {
    b += a[d];
  }
  return b;
});
}).call(window);

The g() function is the compiled version of goog.exportSymbol() – see the @export docs for more details. g()函数是goog.exportSymbol()的编译版本 - 有关更多详细信息,请参阅@export文档

Note: if you want to run the code uncompiled, you'll need to load the Closure Library, or define goog.scope() yourself: 注意:如果要运行未编译的代码,则需要加载Closure库,或者自己定义goog.scope()

var goog = {};
goog.scope = function(fn) {
    fn();
};

Here's a fork of your JSFiddle with all these changes. 是你的JSFiddle一个分支,包含所有这些变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用闭包编译器 ADVANCED_OPTIMIZATIONS 的奇怪对象属性行为 - strange object property behavior with closure compiler ADVANCED_OPTIMIZATIONS Google Closure Compiler ADVANCED_OPTIMIZATIONS - 排除所有函数名称 - Google Closure Compiler ADVANCED_OPTIMIZATIONS - Exclude All function names 是否可以使用闭包编译器ADVANCED_OPTIMIZATIONS与jQuery? - Is it possible to use Closure Compiler ADVANCED_OPTIMIZATIONS with jQuery? Google Closure编译器的ADVANCED_OPTIMIZATIONS选项 - Google Closure Compiler's ADVANCED_OPTIMIZATIONS option 如何在ADVANCED_OPTIMIZATIONS中的Closure Compiler中导出公共类方法? - How to export public class methods in Closure Compiler in ADVANCED_OPTIMIZATIONS? 是否可以避免使用带有getter和setter的模式,而仍然使用Closure ADVANCED_OPTIMIZATIONS最小化JavaScript? - Can a pattern with getters and setters be avoided and still minify JavaScript with Closure ADVANCED_OPTIMIZATIONS? 如何不编译goog.closure中的某些代码ADVANCED_OPTIMIZATIONS - How to not compile certain code in goog.closure ADVANCED_OPTIMIZATIONS 关闭编译ADVANCED_OPTIMIZATIONS抱怨使用此方法 - closure compilation ADVANCED_OPTIMIZATIONS complaining about use of this 具有高级优化和外部功能的Closure编译器 - Closure Compiler with Advanced Optimizations and Externs 闭包编译器,缺少具有高级优化功能的方法? - Closure Compiler, missing method with advanced optimizations?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM