9

在 angular5 上,我尝试对我的大部分模块/组件进行同一个项目的 AOT 编译......但我有一部分需要 JIT 编译。

对于第二部分,HTML 来自 Ajax 请求并包含一些必须由 angular 编译的组件标记。为了管理这部分,我使用如下指令:

export class ArticleLiveDirective implements OnInit, OnChanges, OnDestroy {

    // [...]    

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

    // [...]

    private addHtmlComponent(template: string, properties: any = {}) {
        this.container.clear();
        //Force always rootDomElement.
        const divTag = document.createElement('div');
        divTag.setAttribute('id',this.currentId);
        divTag.innerHTML = template;
        template = divTag.outerHTML;

        // We create dynamic component with injected template
        @Component({ template })
        class ArticleLIveComponent implements OnInit, OnChanges, OnDestroy {
            constructor(
                private articleService: ArticleService
            ) {}
            ngOnInit() {}
            ngOnChanges(changes: SimpleChanges) {}
            ngOnDestroy() {}
            goToPage($event: Event, pagination: string) {
                this.articleService.askToChangeArticle(pagination);
                //Stop propagation
                $event.stopPropagation();
                return false;
            }

        }

        // we declare module with all dependencies
        @NgModule({
            declarations: [
                ArticleLIveComponent
            ],
            imports: [
                BrowserModule,
                MatTabsModule
            ],
            providers: []
        })
        class ArticleLiveModule {}

        // we compile it
        const mod = this.compiler.compileModuleAndAllComponentsSync(ArticleLiveModule);
        const factory = mod.componentFactories.find((comp) =>
            comp.componentType === ArticleLIveComponent
        );
        // fetch instance of fresh crafted component
        const component = this.container.createComponent(factory);
        // we inject parameter.
        Object.assign(component.instance, properties);
    }
}

如您所见,我可以调用addHtmlComponent方法在运行时使用自定义 HTML 作为模板编译新组件。

我的模板看起来像:

<div>
<h2>Foo bar</h2>
<mat-tab-group>
  <mat-tab label="Tab 1">Content 1</mat-tab>
  <mat-tab label="Tab 2">Content 2</mat-tab>
</mat-tab-group>
<p>Other content</p>

一切正常,直到我切换到 AOT 编译(仅供参考:https ://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack )

可能的原因: 我猜主要原因是因为 AOT 编译从输出编译包中删除了 Angular 的“编译器”部分。 我尝试过 的 - 我尝试直接在我的代码上要求它,但仍然不存在。- 我试图检查像角度(或角度材料)这样的网站如何处理它。但不适合我的情况。事实上,两者都已经编译了 AOT 版本中的所有示例。动态部分是样本周围的“只是”内容。

如果您想检查角度材料是如何做到的:每个组件的所有网站示例:https ://github.com/angular/material2/tree/master/src/material-examples

然后他们有加载器: https ://github.com/angular/material.angular.io/blob/master/src/app/shared/doc-viewer/doc-viewer.ts#L85

这可能是正确的方法,但我不知道如何调整它来管理动态标签内容。


编辑:我在这里添加了示例:https ://github.com/yanis-git/aot-jit-angular (分支大师)

正如您将看到的,AOT 编译从包中删除了墙编译器,结果如下:

Module not found: Error: Can't resolve '@angular/compiler/src/config'

我试图在 AppModule 上强制编译器工厂,但仍然没有结果。

我在同一个 repo 上有另一个示例,但是在分支“lazy-jit”上,现在我在输出的包中嵌入了编译器,但是出现了新错误:

ERROR Error: No NgModule metadata found for 'ArticleLiveModule'.

谁看起来与这个问题完全相同:https ://github.com/angular/angular/issues/16033

4

2 回答 2

7

尝试这个:

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

    import { AppComponent } from './app.component';
    import { HelloComponent } from './hello.component';


    import { JitCompilerFactory } from '@angular/platform-browser-dynamic';

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


    @NgModule({
      providers: [
        { provide: COMPILER_OPTIONS, useValue: {}, multi: true },
        { provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] },
        { provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] }
      ],
      imports: [BrowserModule, FormsModule],
      declarations: [AppComponent, HelloComponent],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

代码示例

但是 JitCompiler 仍然无法创建依赖注入树。我怀疑 @Injectable 将从 AOT 部分中删除。但我不能做你的伎俩。

在上面的代码示例中,没有用于 NgModule 和 Component的装饰器。所以,这意味着也没有@Injectable并且他们不能注入providers。那么为什么我们不为@NgModule@Component @Injectable装饰器编写,而只将其写入Services呢?因为,他们有一个装饰器(@NgModule/@Components),Services而不是。它们的装饰器足以让 Angular 知道它们是可注入的。

带有 DI 的代码示例。

更新: 创建自定义包装器CustomNgModuleCustomComponent装饰CustomInjectable器:

export function CustomComponent(annotation: any) {
    return function (target: Function) {
        const component = new Component(annotation);
        Component(component)(target);

    };
}

export function CustomNgModule(annotation: any) {
    return function (target: Function) {
        const ngModule = new NgModule(annotation);
        NgModule(ngModule)(target);
    };
}


export function CustomInjectable() {
  return function (target: Function) {
      const injectable = new Injectable();
      Injectable()(target);
  };
}

使用AOT标志构建时,Angular-CLI 看起来像是从需要动态编译的部分代码中从本地装饰器中清除捆绑包。

如果您想编译带有功能dynamically的组件的模块,请将本机装饰器 ( ) 替换为自定义装饰器,以在编译模式下保留装饰器 :AOTDINgModule/Injectable...AOT

懒惰的.module.ts:

@CustomComponent({
  selector: 'lazy-component',
  template: 'Lazy-loaded component. name:  {{name}}.Service 
           {{service.foo()}}!',
  //providers: [SampleService]
})
export class LazyComponent {
  name;
  constructor(public service: SampleService) {
    console.log(service);
    console.log(service.foo());
  }
}

@CustomNgModule({
  declarations: [LazyComponent],
  providers: [SampleService]
})
export class LazyModule {
}

app.component.ts:

...
 ngAfterViewInit() {

    this.compiler.compileModuleAndAllComponentsAsync(LazyModule)
      .then((factories) => {
        const f = factories.componentFactories[0];    
        const cmpRef = this.vc.createComponent(f);    
        cmpRef.instance.name = 'dynamic';
      });
  }
...

代码示例 3

于 2018-03-24T04:36:10.100 回答
0

我最近遇到了同样的问题,现在放弃了尝试解决。

Afaik 这不能完成(现在),因为angular 删除了生产构建上的元数据

我们应该在问题 8896 关闭后重试。

于 2018-03-22T07:32:11.903 回答