Angular2 (CLI) тряска дерева удаляет динамически созданный NgModule

Я предполагаю, что вопрос об исключающем компоненте Angular-cli исключении из удаления очень похож, но я не могу ничего из этого извлечь.

По сути, у меня есть фабрика динамических компонентов, как описано в разделе Как использовать / создать динамический шаблон для компиляции динамического компонента с Angular 2.0?,

Когда я собираю его, используя последний Angular CLI с непроизводственными настройками, все работает нормально. Однако, как только я использую производственный параметр, я сразу получаю следующую трассировку в браузере при попытке загрузить страницу с динамически создаваемым содержимым:

ИСКЛЮЧЕНИЕ: Метаданные NgModule для 'e' не найдены.
ОРИГИНАЛЬНАЯ СТОРОНА:
main.dc05ae9....bundle.js: отформатирован:4731
Ошибка: метаданные NgModule не найдены для 'e'.
по адресу f (vendor.c18e6df….bundle.js: форматированный:76051)
в t.resolve (vendor.c18e6df….bundle.js: форматированный:20624)
в t.getNgModuleMetadata (vendor.c18e6df….bundle.js: в формате:20169)
в t._loadModules (vendor.c18e6df….bundle.js: форматированный:40474)
в t._compileModuleAndAllComponents (vendor.c18e6df….bundle.js: отформатировано:40462)
в t.compileModuleAndAllComponentsSync (vendor.c18e6df….bundle.js: отформатировано:40436)
в e.createComponentFactory (main.dc05ae9….bundle.js: отформатированный:4789)

Вот мой класс фабрики компонентов:

@Injectable()
export class DynamicTypeBuilder {    
  constructor() {
  }

  private _cacheOfFactories: {[templateKey: string]: ComponentFactory<any>} = {};
  private compiler: Compiler = new JitCompilerFactory([{useDebug: false, useJit: true}]).createCompiler();

  public createComponentFactory<COMPONENT_TYPE>(type: any, template: string, additionalModules: any[] = []): Observable<ComponentFactory<COMPONENT_TYPE>> {

    let factory = this._cacheOfFactories[template];
    if (factory) {
      return Observable.of(factory);
    }

    // unknown template ... let's create a Type for it
    let module = this.createComponentModule(type, additionalModules);

    // compiles and adds the created factory to the cache
    return Observable.of(this.compiler.compileModuleAndAllComponentsSync(module))
                     .map((moduleWithFactories: ModuleWithComponentFactories<COMPONENT_TYPE>) => {
                       factory = moduleWithFactories.componentFactories.find(value => value.componentType == type);
                       this._cacheOfFactories[template] = factory;                           
                       return factory;
                     });
  }

  protected createComponentModule(componentType: any, additionalModules: any[]): Type<any> {
    @NgModule({
      imports: [
        FormsModule,
        ReactiveFormsModule,
        BrowserModule,
        PipesModule,
        ...additionalModules
      ],
      declarations: [
        componentType
      ],
      schemas:[CUSTOM_ELEMENTS_SCHEMA]
    })
    class RuntimeComponentModule {
    }

    return RuntimeComponentModule;
  }
}

который передается

var _ = function() {
    function e() {
        this._cacheOfFactories = {},
        this.compiler = new i.a([{
            useDebug: !1,
            useJit: !0
        }]).createCompiler()
    }
    return e.prototype.createComponentFactory = function(e, t, n) {
        var i = this;
        var _ = this._cacheOfFactories[t];
        if (_)
            r.Observable.of(_);
        var a = this.createComponentModule(e, n);
        return r.Observable.of(this.compiler.compileModuleAndAllComponentsSync(a)).map(function(n) {
            return _ = n.componentFactories.find(function(t) {
                return t.componentType == e
            }),
            i._cacheOfFactories[t] = _,
            _
        })
    }
    ,
    e.prototype.createComponentModule = function(e, t) {
        var n = function() {
            function e() {}
            return e
        }();
        return n
    }
    ,
    e.ctorParameters = function() {
        return []
    }
    ,
    e
}()

"Е" в сообщении об ошибке является функцией e() от createComponentModule который, как вы можете видеть, пуст, хотя он должен содержать @NgModule содержание.

Как я могу динамически создать новый NgModule и при этом использовать производственный режим Angular CLI?

Версии:
Angular2: 2.4.8
Угловой CLI: 1.0.0-бета.32.3
TypeScript: 2.1.6

2 ответа

К сожалению, на данный момент кажется, что это невозможно (я постараюсь сохранить ответ в курсе), ни с Angular 2.x, ни с Angular 4 beta.
Проблема заключается в том, что определение динамического компонента содержит ссылки на файлы (шаблон, таблицы стилей), которые не могут быть решены во время выполнения с помощью компилятора AOT, запущенного ранее.
Но также, если компонент или модуль не будет содержать ссылок на файлы, текущий код Angular не позволяет по-настоящему динамически создавать компоненты. Он просто не находит метаданные, которые создаются во время выполнения.

Подводя итог, можно выделить 3 уровня создания динамических компонентов:

  1. Определите компонент статически и включите его в NgModule, который компилятор AOT может найти во время компиляции AOT. Такой компонент может быть создан в любой момент без проблем. (См. ComponentFactoryResolver и т. Д.)
  2. Определите тело компонента статически (код и т. Д.), Но разрешите иметь динамические шаблоны и / или стили (т. Е. Шаблон создается в коде именно тогда, когда это необходимо). Это также требует компиляции NgModule во время выполнения. В настоящее время это возможно только тогда, когда не используется компилятор AOT, и представляет проблему, которую я разместил здесь.
  3. Динамически определяйте полный компонент, включая код и шаблоны. Это не то, что предназначено здесь и может даже пойти далеко. Но, возможно, у кого-то есть и эта проблема.

На мой взгляд, проблема номер 2 может быть решена. Команда Angular говорит, что, поскольку это AOT, она может компилировать только те вещи, которые статически известны во время компиляции AOT, но я не согласен.
Я мог бы подумать о возможности AOT скомпилировать "заглушку" такого компонента, который затем создается при необходимости с помощью динамического шаблона или таблицы стилей. Там может быть необходимость использовать новое свойство для @Component аннотация или совершенно новая аннотация, как @DynamicComponent но это кажется возможным для меня. Я не знаю, потребуются ли такие же изменения для @NgModule декларация, но я предполагаю, что они будут.

У меня такое же сообщение об ошибке. Обходной путь, который я нашел, состоит в том, чтобы не использовать декоратор для модуля времени выполнения.

protected createComponentModule(componentType: any, additionalModules: any[]): Type<any> {
  return NgModule({
    imports: [
      FormsModule,
      ReactiveFormsModule,
      BrowserModule,
      PipesModule,
      ...additionalModules
    ],
    declarations: [
      componentType
    ],
    schemas:[CUSTOM_ELEMENTS_SCHEMA]
  })(class RuntimeComponentModule {});
}

Ладно, я не до конца понял, почему происходит ошибка. Сообщение об ошибке в основном говорит, что модуль e не имеет метаданных. Метаданные модуля в Angular обычно объявляются как декоратор.

Декораторы в ES7 эквивалентны функциям карри. Это значит

@NgModule({})
class A {}

равно

NgModule({})(class A {})

Лично я считаю, что карри намного лучше...

Обновлен 22 матч: ответ от официального репо https://github.com/angular/angular-cli/issues/5359 просто не использует AOT. Пожалуйста, создайте код с ng build --prod --no-aotВ моем случае все решаемо.

Другие вопросы по тегам