web-dev-qa-db-ja.com

Angular 6/7 AOT:動的テンプレートレンダリング-モジュールのJitCompilerをロード

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コンパイラに含めて、そのメソッドにアクセスする方法はありますか?

関連する質問をいくつか見つけましたが、答えがありません。

Angular 5およびAOT-Build で@angularコンパイラを使用中にエラーが発生しました

EDIT 15.01.2019これはstackblitz.comでの実際のJITの例です補間とデータバインディングテストあり: https://stackblitz.com/github/lyczos/angular-dynamic-html-renderer

EDIT 05.01.2020現在、私は使用を開始しました builder.io Steve(このプロジェクトの作者)はWebコンポーネントを使用していますそれを機能させるために。

7
Lyczos

まず、これを答えとして書いたことをお詫びしますが、コメントとしては長すぎました。

あなたが求めていることをすることは可能です。実際、私は今年のng-confでこの正確な質問を実際に提起しました。このテーマに関する彼のセッションの1つの後、私はMax Koretskyi(別名angularindepth.comの「ng-wizard」著者)と話をしました。

彼が提供したソリューションは非常に複雑でハッキーであり、将来的に壊れないことを信頼することはできませんでしたが、警告する必要がありますAngularリリース、あなたが達成しようとしていることはAngularフレームワークであり、まさにAngularチームが人々の行動を阻止しようとしているのです。本当に、維持しようとするのは悪夢であり、新しい開発者はおそらく、私がしたことを理解しようとして彼らのトップをポップするでしょう。1年以上後に振り返ったら、私が何をしたのかさえわからないでしょう。

最終的に、私はAOTをあきらめることに決め、JITを使用してアプリをデプロイしましたが、それ以来、決定を後悔していません。あなたが本当にこれをさらに追求したいと思うなら、私はマックスに手を差し伸べることを提案します。私がng-confで集めたものから、彼はとてもフレンドリーな人であり、質問があれば彼に連絡するように人々を公然と招待します。それがお役に立てば幸いです。 :)

3
Narm

昨年同じ問題が発生し、修正を見つけることができました。スタイルガイドで動的に生成されたangularコンポーネントを使用していました。これは、AOTコンパイルで機能する実際の例です。

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

import 'core-js/es7/reflect';polyfills.tsに追加することは、重要な非自明なトリックでした。

動的にコンパイルされたコンポーネントをng build --prodで実行するには、

 "buildOptimizer": false,

angle.jsonの本番構成で。 buildOptimizerをオフにすると、バンドルサイズが大きくなる可能性がありますが、少なくとも、ほとんどのコードを事前にコンパイルすることでメリットが得られることに注意してください。

0
crimbo