Angular 6/7 AOT:动态模板渲染 - 为模块加载JitCompiler

问题描述 投票:6回答:2

我有一个问题,即从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构建时

我也尝试在providers[]中的app.module.ts中提供编译器,就像这样,它也不起作用:

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编译器的延迟加载模块来访问它的方法?

我发现了一些相关的问题,但没有答案:

Error while using @angular compiler in Angular 5 and AOT-Build

EDIT 15.01.2019这是一个在stackblitz.com上运行的JIT示例,带有插值和数据绑定测试:https://stackblitz.com/github/lyczos/angular-dynamic-html-renderer

angular dynamic jit aot
2个回答
2
投票

首先,我为写这个作为答案而道歉,但作为评论,它太长了。

你可以做你想要的事情。事实上,我实际上在今年的ng-conf提出了这个问题。在他关于这个主题的一次会议之后,我采访了Max Koretskyi(又名angularindepth.com的“ng-wizard”作者)。

我必须警告你,虽然他提供的解决方案非常复杂,hacky,你不能依赖它在未来的Angular版本中不会破坏,因为你想要实现的是与Angular框架相悖,而正是Angular团队试图阻止人们这样做。真的,这只是一个噩梦,试图保持,任何新的开发者可能会弹出他们的顶部试图弄清楚我做了什么。哎呀我可能甚至不知道如果我回顾一年+之后我做了什么。

最终,我决定放弃AOT并使用JIT部署我的应用程序,因此我没有后悔自己的决定。如果你确定你真的想进一步追求这个,我建议你去接触Max。从我在ng-conf那里收集到的,他是一个非常友好的人,如果他们有疑问,他会公开邀请人们联系他。希望有所帮助,祝你好运! :)


0
投票

我去年遇到了同样的问题,并找到了解决办法。我在我的样式指南中使用动态生成的角度组件。这是一个工作示例,适用于AOT编译:

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

import 'core-js/es7/reflect';添加到polyfills.ts是一个非常明显的关键技巧。

使用ng build --prod运行动态编译的组件也需要

 "buildOptimizer": false,

在angular.json中的生产配置中。请注意,关闭buildOptimizer可能会增加您的捆绑包大小,但至少您将获得预编译大部分代码的好处。

© www.soinside.com 2019 - 2024. All rights reserved.