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

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

问题描述

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

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

导出类 ArticleLiveDirective 实现 OnInit、OnChanges、OnDestroy {//[...]构造函数(私有容器:ViewContainerRef,私有编译器:编译器) { }//[...]私有 addHtmlComponent(模板: 字符串, 属性: any = {}) {this.container.clear();//强制总是rootDomElement.const divTag = document.createElement('div');divTag.setAttribute('id',this.currentId);divTag.innerHTML = 模板;模板 = divTag.outerHTML;//我们用注入的模板创建动态组件@Component({模板})类 ArticleLIveComponent 实现 OnInit、OnChanges、OnDestroy {构造函数(私人文章服务:文章服务) {}ngOnInit() {}ngOnChanges(changes: SimpleChanges) {}ngOnDestroy() {}goToPage($event: 事件, 分页: 字符串) {this.articleService.askToChangeArticle(分页);//停止传播$event.stopPropagation();返回假;}}//我们声明具有所有依赖项的模块@NgModule({声明: [文章实时组件],进口:[浏览器模块,MatTabs 模块],提供者:[]})class ArticleLiveModule {}//我们编译它const mod = this.compiler.compileModuleAndAllComponentsSync(ArticleLiveModule);const factory = mod.componentFactories.find((comp) =>comp.componentType === ArticleLIveComponent);//获取新制作的组件的实例const 组件 = this.container.createComponent(factory);//我们注入参数.Object.assign(component.instance, properties);}}

如您所见,我可以调用 addHtmlComponent 方法在运行时使用自定义 HTML 作为模板编译新组件.

我的模板看起来像:

<h2>Foo bar</h2><mat-tab-group><mat-tab label="Tab 1">内容 1</mat-tab><mat-tab label="Tab 2">内容 2</mat-tab></mat-tab-group><p>其他内容</p>

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

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

如果你想检查角材料是如何做到的:每个组件的所有网站示例:https://github.com/angular/material2/tree/master/src/material-examples

然后他们有 loader :https://github.com/angular/material.angular.io/blob/master/src/app/shared/doc-viewer/doc-viewer.ts#L85

这可能是正确的方法,但我不知道如何使其适应管理动态标签内容.

<小时>

编辑:我在这里添加了示例:https://github.com/yanis-git/aot-jit-angular (branch Master)

正如你将看到的,AOT 编译从包中删除了墙编译器,这个结果:

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

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

我在同一个 repo 上有另一个示例,但是在分支lazy-jit"上,现在我将编译器嵌入到输出包中,但是出现了新错误:

ERROR 错误:未找到ArticleLiveModule"的 NgModule 元数据.

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

解决方案

试试这个:

 import { Compiler, COMPILER_OPTIONS, CompilerFactory, NgModule } from '@angular/core';从 '@angular/platform-b​​rowser' 导入 { BrowserModule, };从'@angular/forms'导入{FormsModule};从 './app.component' 导入 { AppComponent };import { HelloComponent } from './hello.component';从'@angular/platform-b​​rowser-dynamic'导入{JitCompilerFactory};导出函数 createCompiler(compilerFactory: CompilerFactory) {返回 compilerFactory.createCompiler();}@NgModule({供应商: [{ 提供:COMPILER_OPTIONS,useValue:{},multi:true },{ 提供:CompilerFactory,useClass:JitCompilerFactory,deps:[COMPILER_OPTIONS] },{ 提供:编译器,useFactory:createCompiler,deps:[CompilerFactory] ​​}],进口:[BrowserModule,FormsModule],声明:[AppComponent,HelloComponent],引导程序:[AppComponent]})导出类 AppModule { }

代码示例

<块引用>

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

在上面的代码示例中,NgModule 和组件没有装饰器.所以,这意味着也没有 @Injectable 并且他们不能注入 providers.那么为什么我们不为 @NgModule@Component @Injectable 装饰器编写代码,而只将其写入服务?因为,他们有装饰器(@NgModule/@Components),Services 没有.它们的装饰器足以让 Angular 知道它们是可注入的.

代码示例与 DI.

更新:创建自定义包装器 CustomNgModuleCustomComponentCustomInjectable 装饰器:

export function CustomComponent(annotation: any) {返回函数(目标:函数){const 组件 = 新组件(注释);组件(组件)(目标);};}导出函数 CustomNgModule(annotation: any) {返回函数(目标:函数){const ngModule = 新的 NgModule(注释);NgModule(ngModule)(目标);};}导出函数 CustomInjectable() {返回函数(目标:函数){const 可注射 = 新可注射();可注射()(目标);};}

<块引用>

当使用 AOT 标志构建时,Angular-CLI 看起来像清理包来自需要编译的代码部分的本地装饰器动态.

在你想要的地方动态编译带有组件的模块在带有 DI 功能的 AOT 中,替换原生装饰器(NgModule/Injectable...) 用自定义的一个来保留装饰器AOT 编译方式:

lazy.module.ts:

@CustomComponent({选择器:'懒惰组件',模板:'延迟加载的组件.名称:{{name}}.Service{{service.foo()}}!',//提供者:[SampleService]})导出类 LazyComponent {姓名;构造函数(公共服务:SampleService){控制台日志(服务);console.log(service.foo());}}@CustomNgModule({声明:[LazyComponent],提供者:[SampleService]})导出类 LazyModule {}

app.component.ts:

<预><代码>...ngAfterViewInit() {this.compiler.compileModuleAndAllComponentsAsync(LazyModule).then((工厂) => {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天全站免登陆