web-dev-qa-db-fra.com

aOT angulaire et JIT sur le même projet

Sur angular5, j’essaie d’avoir sur le même projet la compilation AOT pour la plupart de mes modules/composants ... mais j’ai une partie qui doit être compilée JIT.

Pour cette seconde partie, HTML provient de la requête Ajax et contient quelques balises de composant qui doivent être compilées par angular. Pour gérer cette partie, j'utilise une directive qui ressemble à: 

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);
    }
}

Comme vous pouvez le constater, je peux appeler addHtmlComponent pour compiler un nouveau composant à l'exécution avec du code HTML personnalisé comme modèle. 

Mon modèle ressemble à: 

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

tout fonctionne parfaitement jusqu’à ce que je passe à la compilation AOT (pour l’instant je l’utilise: https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack

Raison possible: Je suppose que la raison principale est parce que la compilation AOT supprime le "compilateur" de la partie de Angular du paquet compilé en sortie. Ce que je have try - J'ai essayé de l'exiger directement sur mon code, mais il n'est toujours pas présent. - J'ai essayé de vérifier comment des sites Web tels que angular (ou un matériau angulaire) y font face. Mais n'est pas adapté à mon cas. En fait, ils ont déjà une version compilée de tous les exemples de la version AOT. La partie dynamique est "juste" du contenu autour de l'échantillon.

Si vous souhaitez vérifier comment le matériau angulaire le fait: Tous les exemples de site Web pour chaque composant: https://github.com/angular/material2/tree/master/src/material-examples

Ensuite, ils ont le chargeur: https://github.com/angular/material.angular.io/blob/master/src/app/shared/doc-viewer/doc-viewer.ts#L85

C'est peut-être la bonne façon de le faire mais je ne sais pas comment l'adapter pour gérer, le contenu dynamique des onglets.


EDIT: j'ai ajouter un échantillon ici: https://github.com/yanis-git/aot-jit-angular (branche master)

Comme vous le verrez, la compilation AOT supprime le compilateur mural de l’ensemble, ce qui suit: 

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

J'ai essayé de forcer compilater Factory sur AppModule, mais toujours aucun résultat.

J'ai un autre échantillon sur le même dépôt, mais sur la branche "lazy-jit", maintenant j'ai compiler incorporé sur le paquet sorti, mais une nouvelle erreur me vient à l'esprit: 

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

Qui a l'air d'être exactement le même que ce problème: https://github.com/angular/angular/issues/16033

9
Yanis-git

Essaye ça:

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

EXEMPLE DE CODE

Mais JitCompiler ne peut toujours pas créer d'arborescence Injection de dépendance. Je Soupçonne que @Injectable est retiré de la partie AOT. Mais je ne peux pas faire votre tour .

Dans l'exemple de code ci-dessus, il n'y a pas décorateurs pour NgModule et Component. Donc, cela signifie qu’il n’ya pas @Injectable aussi et qu’ils ne peuvent pas injecter providers. Alors pourquoi ne pas écrire pour @NgModule et @Component @Injectable decorator et ne l'écrire que dans Services ? Parce qu’ils ont un décorateur (@ NgModule/@ Components), Services not. Et leurs décorateurs sont suffisants pour Angular savoir qu'ils sont injectable

EXEMPLE DE CODE avec DI.

UPDATE: Décorateurs personnalisés créés CustomNgModule, CustomComponent et CustomInjectable décorators:

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);
  };
}

Lors de la construction avec l'indicateur AOT, Angular-CLI ressemble à un paquet de nettoyage Des décorateurs natifs à partir de parties de code devant être compilées De manière dynamique.

Et si vous voulezdynamicallycompiler des modules avec des composants Dans AOT avec une fonctionnalité DI, remplacez les décorateurs natifs (NgModule/Injectable...) par un composant personnalisé pour les conserver dans AOT mode de compilation:

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

EXEMPLE DE CODE 3

5
Yerkon

J'ai fait face au même problème récemment et j'ai cessé d'essayer de le résoudre pour le moment.

Autrement, cela ne peut pas être fait (pour le moment) car angular supprime les métadonnées sur la production .

Nous devrions réessayer après la fermeture du numéro 8896.

0