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

时间:2018-12-20 13:11:56

标签: angular dynamic jit aot

我在通过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编译中完成这项工作,因为现在出现错误: 在示例代码上使用AoT构建时,Runtime Compiler is not loaded

我还尝试在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

编辑15.01.2019 这是 stackblitz.com 上使用插值和数据绑定测试的有效JIT示例: https://stackblitz.com/github/lyczos/angular-dynamic-html-renderer

2 个答案:

答案 0 :(得分:2)

首先,我很抱歉将其写为答案,但作为评论太久了。

可以按照您的要求进行操作。实际上,我今年确实在ng-conf上提出了这个确切的问题。在就此主题进行了一次会议之后,我与Max Koretskyi(又名angularindepth.com的“ ng-wizard”作者)进行了交谈。

我必须警告您,尽管他提供的解决方案非常复杂,棘手,并且您不能依靠它在将来的Angular版本中不会中断,因为您要实现的目标与Angular框架背道而驰Angular团队正试图阻止人们这样做。真的,要维护它只是一场噩梦,任何新的开发人员都可能会冒出顶峰,试图了解我所做的事情。哎呀,如果我一年后再回顾一下,我什至不知道我做了什么。

最终,我决定放弃AOT,并使用JIT部署了我的应用程序,此后我就不后悔自己的决定。如果您确定您真的想进一步追求这个目标,我建议您与Max取得联系。从我在ng-conf上收集的信息来看,他是一个非常友好的人,他公开邀请人们在遇到问题时与他联系。希望能有所帮助,祝您好运! :)

答案 1 :(得分:0)

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

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

import 'core-js/es7/reflect';添加到polyfills.ts是关键的非显而易见的技巧。

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

 "buildOptimizer": false,

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