角度AOT和JIT在同一项目上 [英] angular AOT and JIT on same project

查看:117
本文介绍了角度AOT和JIT在同一项目上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  export class ArticleLiveDirective实现OnInit,OnChanges,OnDestroy {

// [...]

构造函数(
私有容器:ViewContainerRef,
私有编译器:编译器
){}

// [...]

私人addHtmlComponent(template:string,properties:any = {}){
this.container.clear();
//强制始终使用rootDomElement。
const divTag = document.createElement(’div’);
divTag.setAttribute(’id’,this.currentId);
divTag.innerHTML =模板;
template = divTag.outerHTML;

//我们使用注入的模板
@Component({template})创建动态组件
类ArticleLIveComponent实现OnInit,OnChanges,OnDestroy {
构造函数(
私人articleService:ArticleService
){}
ngOnInit(){}
ngOnChanges(更改:SimpleChanges){}
ngOnDestroy(){}
goToPage($ event :事件,分页:字符串){
this.articleService.askToChangeArticle(pagination);
//停止传播
$ event.stopPropagation();
返回false;
}

}

//我们声明具有所有依赖项的模块
@NgModule({
声明:[
ArticleLIveComponent
],
导入:[
BrowserModule,
MatTabsModule
],
提供者:[]
})
类ArticleLiveModule {}

//我们将其编译为
const mod = this.compiler.compileModuleAndAllComponentsSync(ArticleLiveModule);
const factory = mod.componentFactories.find((comp)=>
comp.componentType === ArticleLIveComponent
);
//获取新制作的组件的实例
const component = this.container.createComponent(factory);
//我们注入参数。
Object.assign(component.instance,properties);
}
}

您可以看到我可以呼叫 addHtmlComponent 方法,以自定义HTML作为模板在运行时编译新组件。



我的模板如下:

 ÷ div; 
< h2> Foo bar< / h2>
< mat-tab-group>
< mat-tab label =标签1>内容1< / mat-tab>
< mat-tab label =标签2>内容2< / mat-tab>
< / mat-tab-group>
< p>其他内容< / p>



一切正常,直到我切换到AOT编译(供我使用: https:// github。 com / angular / angular-cli / tree / master / packages /%40ngtools / webpack



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



如果要检查角度材料的作用方式:
每个组件的所有网站示例: https://github.com/angular/material2/tree/master/src/material-示例



然后他们有了装载程序:
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编译删除软件包中的墙编译器,结果如下:

 找不到模块:错误:无法解析'@ angular / compiler / src / config'

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



我在相同的仓库中有另一个样本,但是在分支 lazy-jit上,现在我在输出的包中嵌入了Compiler,但是出现了新的错误:

 错误错误:找不到 ArticleLiveModule的NgModule元数据。 

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

解决方案

尝试一下:

  import {Compiler,COMPILER_OPTIONS,CompilerFactory,NgModule}从'@角/芯'; 
import {BrowserModule,} from'@ angular / platform-b​​rowser';
从 @ angular / forms导入{FormsModule};

从 ./app.component导入{AppComponent};
从 ./hello.component导入{HelloComponent};


从 @ angular / platform-b​​rowser-dynamic导入{JitCompilerFactory};

导出函数createCompiler(compilerFactory:CompilerFactory){
return CompilerFactory.createCompiler();
}


@NgModule({
提供者:[
{提供:COMPILER_OPTIONS,useValue:{},multi:true},
{提供:CompilerFactory,useClass:JitCompilerFactory,deps:[COMPILER_OPTIONS]},
{提供:Compiler,useFactory:createCompiler,deps:[CompilerFactory]}
],
导入:[BrowserModule ,FormsModule],
声明:[AppComponent,HelloComponent],
引导程序:[AppComponent]
})
导出类AppModule {}

代码示例


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


在上面的代码示例中,没有装饰器用于NgModule和Component。因此,这意味着也没有 @Injectable ,他们也无法注入提供者。那么为什么我们不写 @NgModule @Component @Injectable 装饰器,而只将其写入 Services
因为它们有装饰器(@ NgModule / @ Components),服务没有。而且,它们的装饰器足以使Angular知道其可注射



带有DI的代码示例



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

 导出函数CustomComponent(注释:任意){
返回函数(目标:函数){
const component = new Component(注释);
Component(component)(target);

};
}

导出函数CustomNgModule(annotation:any){
return function(target:Function){
const ngModule = new NgModule(annotation);
NgModule(ngModule)(目标);
};
}


导出函数CustomInjectable(){
返回函数(目标:函数){
const injectable = new Injectable();
Injectable()(目标);
};
}




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



在需要的地方 动态 AOT 的模块c>具有 DI 功能,将自定义修饰符
NgModule / Injectable ... )替换为自定义修饰符以
AOT 编译模式保留装饰器:


lazy.module.ts:

  @CustomComponent({
选择器:'lazy-component' ,
模板:延迟加载的组件。名称:{{name}}。服务
{{service.foo()}}!,
//提供者:[SampleService]
})
导出类LazyComponent {
name;
构造函数(公共服务:SampleService){
console.log(service);
console.log(service.foo());
}
}

@CustomNgModule({
声明:[LazyComponent],
提供者:[SampleService]
})
出口类LazyModule {
}

app.component.ts:

  ... 
ngAfterViewInit(){

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

代码示例3


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

解决方案

Try this:

    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

But JitCompiler still not able to create Dependency Injection tree. I suspect @Injectable to be remove from AOT part. But i can't do your trick.

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 and CustomInjectable decorators:

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

When building with AOT flag, Angular-CLI looks like cleans bundle from native decorators from parts of code which need to be compiled dynamically.

And where you want dynamically compile modules with components in AOT with DI functionality, replace native decorators (NgModule/Injectable...) with custom one to preserve decorators in AOT compilation mode:

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

这篇关于角度AOT和JIT在同一项目上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆