On angular5, i try to have on same project AOT compilation for most of my module/component... but i have one part who need to be JIT compiled.
For this second part, HTML come from Ajax request and contain some component tag who must be compiled by angular. To Manage this part i use directive who looks like :
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);
}
}
As you can see i can call addHtmlComponent method to compile new component on runtime with custom HTML as template.
My template looks like :
<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>
everything work perfectly until i switch to AOT compilation (fyi i use : https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack)
Possible reason : Main reason i guess is because AOT compilation delete "compiler" part of Angular from output compiled bundle. What i have try - I have try to require it directly on my code but still is not present. - I have try to check how website like angular (or angular material) deal with it. But is not fit with my case. In fact, both already have compiled version of all examples in AOT version. Dynamic part is "just" content around sample.
If you want to check how angular material do it : All Website examples for each component : https://github.com/angular/material2/tree/master/src/material-examples
Then they have loader : https://github.com/angular/material.angular.io/blob/master/src/app/shared/doc-viewer/doc-viewer.ts#L85
Is may be right way to do it but i am don't know how to adapt it to manage, dynamic Tab content.
EDIT : i have add sample here : https://github.com/yanis-git/aot-jit-angular (branch Master)
As you will see, AOT compilation remove wall compiler from bundle, this result :
Module not found: Error: Can't resolve '@angular/compiler/src/config'
I have try to force compilater Factory on AppModule, but still no result.
I have another sample on same repo, but on branch "lazy-jit", now i have Compiler embed on the outputed bundle, but new error come to me :
ERROR Error: No NgModule metadata found for 'ArticleLiveModule'.
Who looks to be exactly same than this issue : https://github.com/angular/angular/issues/16033
I've faced with same issue recently and gave up trying to solve for now.
Afaik this can not be done (for now) because angular removes metadata on production build.
We should try again after issue 8896 closed.
Try this:
CODE EXAMPLE
In code example above, there is no decorators for NgModule and Component. So, it means there is no @Injectable too and they can't inject
providers
. So why we don't write for @NgModule and @Component @Injectable decorator and only write it to Services? Because, they have a decorators(@NgModule/@Components),Services
not. And their decorators is sufficient for Angular to know that their are injectable.CODE EXAMPLE with DI.
UPDATE: Created custom wrapper
CustomNgModule
,CustomComponent
andCustomInjectable
decorators:lazy.module.ts:
app.component.ts:
CODE EXAMPLE 3