Angular 6/7 AOT: динамический рендеринг шаблона - загрузить JitCompiler для модуля - PullRequest
0 голосов
/ 20 декабря 2018

У меня проблема со сборкой шаблонов "на лету" из ответа API, но только в сборке AoT.

Я получил от бэкэнда такой ответ:

<h1>Title...</h1> 
<some-component></some-componen> 
<p>other content</p>

И яхочу разобрать это как обычный шаблон Angular.

Упрощенный код моего компонента выглядит следующим образом:


        import {
          Compiler,
          Component,
          ComponentFactory,
          ComponentRef,
          Injector,
          Input,
          NgModule,
          OnChanges,
          OnDestroy,
          OnInit,
          ViewContainerRef
        } from '@angular/core';
        import { CommonModule } from '@angular/common';
        import { RouterModule } from '@angular/router';

        export async function createComponentFactory(compiler: Compiler, metadata: Component): Promise> {
          const cmpClass = class DynamicComponent {
          };
          const decoratedCmp = Component(metadata)(cmpClass);

          // IMPORT ALL MODULES HERE!!!
          @NgModule({imports: [CommonModule, RouterModule], declarations: [decoratedCmp]})
          class DynamicHtmlModule {
          }

          const moduleWithComponentFactory = await compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule);
          return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
        }

        @Component({
          selector: 'html-renderer',
          templateUrl: './html-renderer.component.html',
          styleUrls: ['./html-renderer.component.scss']
        })
        export class HtmlRendererComponent implements OnInit, OnChanges, OnDestroy {

          @Input() content: string; 
          cmpRef: ComponentRef;

          constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { }

          ngOnInit(): void {
            console.log('init...')
            console.log(this.compiler)
          }

          ngOnDestroy() {
            if (this.cmpRef) {
              this.cmpRef.destroy();
            }
          }

          ngOnChanges() {
            const html = this.content;
            if (!html) { return; }

            if (this.cmpRef) {
              this.cmpRef.destroy();
            }

            const compMetadata = new Component({
              selector: 'dynamic-selector',
              template: this.content,
            });

            createComponentFactory(this.compiler, compMetadata)
              .then(factory => {
                const injector = Injector.create({providers: [], parent: this.vcRef.injector});
                this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
              });
          }


        }

Итак, я передаю целые данные на вход content, затем компилирую все компонентычерез compileModuleAndAllComponentsAsync метод (https://angular.io/api/core/Compiler#compilemoduleandallcomponentssync) и все работает в сборке JIT .

Я хочу получить эту работу в компиляции AoT, потому что теперь я получаю ошибку: Runtime Compiler is not loaded при сборке с AoT на примере кода

Я также пытался предоставить компилятор в приложении.module.ts в providers[] как этот, но он тоже не работает:

export function createCompiler(compilerFactory: CompilerFactory) {
  return compilerFactory.createCompiler();
}    

    {provide: COMPILER_OPTIONS, useValue: {}, multi: true},
    {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
    {provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory]},

Мой вопрос: есть ли способ включить загруженный ленивый модуль с JIT-компилятором дляполучить доступ к его методам?

Я нашел несколько связанных вопросов, но ответа нет:

Ошибка при использовании @angular компилятора в Angular 5 и AOT-Build

РЕДАКТИРОВАТЬ 15.01.2019 Вот рабочий пример JIT на stackblitz.com с тестом интерполяции и привязки данных: https://stackblitz.com/github/lyczos/angular-dynamic-html-renderer

Ответы [ 2 ]

0 голосов
/ 22 марта 2019

Я столкнулся с той же проблемой в прошлом году и смог найти решение.Я использовал динамически генерируемые угловые компоненты в моем руководстве по стилю.Вот рабочий пример, который работает с компиляцией AOT:

https://github.com/johncrim/angular-dynamic-styleguide

Добавление import 'core-js/es7/reflect'; к polyfills.ts было критической неочевидной уловкой.

Запуск динамически скомпилированных компонентовс ng build --prod также требуется

 "buildOptimizer": false,

в производственной конфигурации в angular.json.Обратите внимание, что отключение buildOptimizer, вероятно, увеличит размер вашего пакета, но, по крайней мере, вы получите преимущество от предварительной компиляции большей части кода.

0 голосов
/ 20 декабря 2018

Во-первых, я прошу прощения за то, что написал это как ответ, но это было слишком долго, чтобы исправить как комментарий.

Возможно сделать то, что вы просите.На самом деле, я поставил этот вопрос на нг-конф в этом году.Я поговорил с Максом Корецким (он же автор «ng-wizard» на angularindepth.com) после одной из его сессий на эту тему.

Я должен предупредить вас, хотя предложенное им решение было очень замысловатым, хакерским, и вы не могли полагаться на то, что оно не сломается в будущих версиях Angular, потому что то, что вы пытаетесь достичь, идет вразрез с платформой Angular иэто именно то, что команда Angular пытается помешать людям делать.На самом деле это был бы просто кошмар, чтобы попытаться поддерживать, и любые новые разработчики, вероятно, выскакивают из своих вершин, пытаясь понять, что я сделал.Черт возьми, я бы даже не знал, что я сделал, если бы оглянулся назад на год + позже.

В конечном итоге я решил отказаться от AOT и развернул свое приложение с использованием JIT, и с тех пор я не сожалел о своем решении.Если вы решите, что действительно хотите продолжить это, я бы предложил обратиться к Максу.Из того, что я собрал на нг-конфе, он довольно дружелюбный парень, и он открыто приглашает людей обратиться к нему, если у них есть вопросы.Надеюсь, что это помогает, удачи!:)

...