代码之家  ›  专栏  ›  技术社区  ›  Yanis-git

同一项目上的角度AOT和JIT

  •  9
  • Yanis-git  · 技术社区  · 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);
        }
    }
    

    如你所见,我可以打电话 添加HTMLComponent 方法在运行时以自定义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

    Is可能是正确的方法,但我不知道如何调整它来管理动态选项卡内容。


    编辑 :我在此处添加了示例: https://github.com/yanis-git/aot-jit-angular (分支主控)

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

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

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

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

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

    谁看起来和这个问题完全一样: https://github.com/angular/angular/issues/16033

    2 回复  |  直到 7 年前
        1
  •  7
  •   Yerkon    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 { }
    

    CODE EXAMPLE

    但JitCompiler仍然无法创建依赖项注入树。我 可疑@Injectable将从AOT部件中移除。但我不能做你的 戏法

    在上面的代码示例中,没有 装饰师 用于NgModule和Component。所以,这意味着没有 @可注射的 他们也不能注射 providers 。那我们为什么不为 @NgModule模块 @组件 @可注射的 装潢师,只写给 服务 ? 因为他们有一个装饰器(@NgModule/@Components), Services 不他们的装饰师足以让Angular知道他们 可注射的

    CODE EXAMPLE 使用DI。

    更新时间: 已创建自定义包装 CustomNgModule ,则, CustomComponent 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 使用组件编译模块 在里面 AOT公司 具有 DI 功能,替换本机装饰器 ( NgModule/Injectable... )定制一个,以保护装饰师 AOT公司 编译模式:

    懒惰的单元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 {
    }
    

    应用程序。组成部分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

        2
  •  0
  •   Halil İbrahim Karaalp    7 年前

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

    Afaik(目前)不能这样做,因为 angular removes metadata on production build

    我们应该在第8896期结束后重试。