2015-04-19 2 views
3

Я знаю, что подобные вопросы заданы раньше, но методология быстро меняется, поэтому я пытаюсь понять текущие лучшие практики. (На самом деле, в последнее время, как 2 дня назад, Чад Killingsworth добавил комментарий к accepted answer от трех лет назад, что @expose аннотаций теперь осуждается.)Схема модуля с компилятором Closure и ADVANCED_OPTIMIZATIONS

Я использую module pattern. Работа 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;* 

В настоящее время, используя @expose аннотацию, выше, может быть минимизирован с закрытием в заранее режиме и следующие вызовы работают (minified example):

// 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); 

Если это возможно, без изменения от шаблона модуля, я хотел бы обновить код (приблизительно 10 000 строк), чтобы использовать аннотацию @export. Однако, когда я заменяю @expose с @export Закрытие поднимает эту ошибку:

ERROR - @export only applies to symbols/properties defined in the global scope.

Q: Можно ли, и если да, то как выше код аннотироваться работать с ADVANCED_OPTIMIZATIONS?

Я знаю, что я могу, возможно, использовать этот тип записи:

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

но экспортирующие свойств объекта таким образом, становится утомительным. Далее JSLint жалуется на странные назначения, поэтому я предпочел бы использовать аннотацию JSDocs.

+0

'@ export' - правильный метод. Похоже, нам нужно будет немного поработать над этим типом использования. –

+1

Проблема добавлена ​​https://github.com/google/closure-compiler/issues/912 –

+0

@ChadKillingsworth, спасибо, что подняли билет на выпуск. Было бы здорово, если поддержка нотации '@ expose' не будет удалена до тех пор, пока' @ export' не поддержит этот шаблон для '@ expose', в настоящее время работает нормально для этого случая. – Karl

ответ

0

До the issue raised by @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; 
    }; 

}); 

Изменения:

  • Изменение @expose теги к @export ,
  • Создайте пустой объект MATHCALCS вне функции обертки модуля и укажите ему псевдоним MY.
  • Вместо немедленного выполнения функции обертки модуля (IIFE) передайте его на goog.scope(). Это позволяет сглаживать функции области видимости, позволяя компилятору определить, что экспортируемые символы определяются на глобальном объекте MATHCALCS. Это предотвращает сбор компилятора ошибки («@export применяется только к символам/свойствам, определенным в глобальной области»).
  • Удалите следующие элементы, которые не нужны:
    • В @export метки на this.color и this.size
    • return MY;
    • window["MATHCALCS"] = MATHCALCS;

При компиляции с помощью этой команды:

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);' 

вы получите:

(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); 

g() функция скомпилированная версия goog.exportSymbol() - см the @export docs для более подробной информации.

Примечание: если вы хотите запустить код Неоткомпилированная, вам необходимо загрузить Closure Library, или определить goog.scope() себя:

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

Вот a fork of your JSFiddle со всеми этими изменениями.

+0

Ницца! Работа хорошо сделана. Спасибо, что нашли время. – Karl

Смежные вопросы