首页 文章

同一项目的角度AOT和JIT

提问于
浏览
7

在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

Possible reason : 我猜的主要原因是因为AOT编译从输出编译的bundle中删除了Angular的一部分"compiler" . What i have try - 我试图直接在我的代码上要求它但仍然不存在 . - 我试着检查像角度(或角度材料)的网站如何处理它 . 但是不符合我的情况 . 实际上,两者都已经在AOT版本中编译了所有示例的版本 . 动态部分是样本周围的"just"内容 .

如果您想检查角度材料的作用方式:每个组件的所有网站示例: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

可能是正确的方法,但我不知道如何适应它来管理,动态Tab内容 .


EDIT :我在这里添加样本:https://github.com/yanis-git/aot-jit-angular(分支大师)

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

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

我试图在AppModule上强制compilater Factory,但仍然没有结果 .

我在同一个repo上有另一个示例,但在分支“lazy-jit”上,现在我将Compiler嵌入到输出的包中,但是新的错误出现在我面前:

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

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

2 回答

  • 0

    试试这个:

    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 { }
    

    CODE EXAMPLE

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

    在上面的代码示例中,NgModule和Component没有 decorators . 所以,这意味着没有 @Injectable 也无法注入 providers . 那么为什么我们不为 @NgModule@Component @Injectable decorator编写并只将其写入 Services ?因为,他们有装饰器(@ NgModule / @ Components), Services 没有 . 他们的装饰者足以让Angular知道他们是 injectable .

    CODE EXAMPLE与DI .

    UPDATE: 创建自定义包装器 CustomNgModuleCustomComponentCustomInjectable 装饰器:

    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看起来像是从需要动态编译的代码部分中清除本机装饰器的包 . 并且您希望在具有DI功能的AOT中使用组件动态编译模块,将自然装饰器(NgModule / Injectable ...)替换为自定义装饰器以在AOT编译模式下保留装饰器:

    lazy.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';
          });
      }
    ...
    

    CODE EXAMPLE 3

  • 3

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

    Afaik这不能(现在)因为angular removes metadata on production build .

    我们应该在8896关闭后再试一次 .

相关问题