Невозможно использовать асинхронный канал в шаблоне динамически генерируемого компонента в динамически генерируемом угловом модуле в режиме AOT - PullRequest
1 голос
/ 17 апреля 2019

Отказ от ответственности: этот вопрос был вдохновлен "" Вот что вам нужно знать о динамических компонентах в Angular"пост на Medium.

Там автор показывает, как можно динамически генерировать как модуль, так и компонент, поместить последний в первый, скомпилировать модуль на лету, получить фабрику компонентов и использовать ее для генерации компонента с помощью ViewContainerRef .

Это просто отлично работает в базовой настройке.

Теперь давайте предположим, что мы хотели бы динамически генерировать компонент, но на этот раз с шаблоном, который использует async pipe.

Далее нам нужно, чтобы эта штука работала в производственной среде, что означает две вещи:

  • AOT включен
  • enableProdMode () было вызвано при начальной загрузке приложения

Поскольку угловой компилятор недоступен, мы можем предоставить экземпляр jit-компилятора для токена компилятора в корневом модуле приложения.

app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import {Compiler, NgModule} from '@angular/core';

import {AppComponent } from './app.component';
import {JitCompilerFactory} from '@angular/platform-browser-dynamic';

export function jitCompiler() {
  /*
   * Cast JitCompilerFactory to any because
   * jit compiler factory constructor does not
   * accept any arguments according to the @angular/platform-browser-dynamic/src/compiler_factory.d.ts
   */
  const klass = (JitCompilerFactory as any);
  return new klass([]).createCompiler([
    {
      useJit: true
    }
  ]);
}

@NgModule({
  declarations: [
    AppComponent
  ],
  providers: [
    {
      provide: Compiler,
      useFactory: jitCompiler
    }
  ],
  imports: [
    BrowserModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import {
  AfterViewInit,
  ChangeDetectionStrategy,
  Compiler,
  Component,
  NgModule,
  ViewContainerRef
} from '@angular/core';
import {Subject} from 'rxjs';
import {CommonModule} from '@angular/common';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements AfterViewInit {
  constructor(
    private readonly compiler: Compiler,
    private readonly vcr: ViewContainerRef
  ) {}
  ngAfterViewInit() {
    const template = '<span>Hello, {{text$ }}</span>';
    const cmp = Component({
      template
    })(class DynamicComponent {
      text$: Subject<string>;
    });

    const module = NgModule({
      declarations: [cmp],
      imports: [CommonModule],
      providers: []
    })(class DynamicModule {});

    this.compiler.compileModuleAndAllComponentsAsync(module)
      .then(compiledModule => {
        const dynamicComponent = this.vcr.createComponent(compiledModule.componentFactories[0]);

        const sub = new Subject();
        sub.next('World!');
        dynamicComponent.instance.text$ = sub;

        // Just to simulate some server updates
        setTimeout(() => dynamicComponent.instance.text$.next('Another'), 3e3);
      });
  }
}

Если мы запустим это и откроем DevTools, мы увидим следующую ошибку:

ОШИБКА Ошибка: неожиданное значение 'function () {}' импортировано модулем 'Функция () {}'. Пожалуйста, добавьте аннотацию @NgModule.

Проблема возникает только в режиме разработки. Угловая версия 7.2.0.

Отсюда вопрос - что нужно сделать, чтобы он работал в режиме AOT?

...