角度8中的延迟加载模块 [英] Lazy load module in angular 8

查看:81
本文介绍了角度8中的延迟加载模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个仪表板应用程序,在这里我懒惰地加载小部件(与路线无关).

我通过定义对象{name: string, loadChildren: string}来做到这一点.然后在我的app.module中,我将执行provideRoutes(...).

这将导致cli为每个小部件模块创建一个块.

然后在运行时,我将使用SystemJsModuleLoader加载该字符串并获得一个NgModuleRef.

我可以从模块中创建组件,然后在ViewContainerRef上调用createComponent.

以下是该功能:

  loadWidget(
    name: string,
    container: ViewContainerRef,
    widget: Widget
  ): Promise<{ instance: WidgetComponent; personlize?: { comp: any; factory: ComponentFactoryResolver } }> {
    if (this.lazyWidgets.hasOwnProperty(name)) {
      return this.loader.load(this.lazyWidgets[name]).then((moduleFactory: NgModuleFactory<any>) => {
        const entryComponent = (<any>moduleFactory.moduleType).entry;
        const moduleRef = moduleFactory.create(this.injector);
        const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);

        const comp = container.createComponent(compFactory);
        (<WidgetComponent>comp.instance).widget = widget;
        const personalize = (<any>moduleFactory.moduleType).personalize;
        if (personalize) {
          return {
            instance: <WidgetComponent>comp.instance,
            personlize: {
              comp: personalize,
              factory: moduleRef.componentFactoryResolver,
              injector: moduleRef.injector
            }
          };
        } else {
          return {
            instance: <WidgetComponent>comp.instance
          };
        }
      });
    } else {
      return new Promise(resolve => {
        resolve();
      });
    }
 

在角度8中,loadChildren更改为导入功能.

您将获得实际的模块实例,而不是NgModuleRef.

我认为我可以通过采用该模块来对其代码进行修复,对其进行编译以获得NgModuleRef,然后将其余代码保持相同.

尽管编译器未捆绑,但似乎在AOT模式下.

因此,我现在基本上只能使用所需的组件实例,但是无法将其添加到View容器中.

它需要一个我无法获得的组件工厂解析器.

我想我的问题是如何获取一个组件实例并将其添加到角度8的视图容器中.现在我已经恢复为使用字符串版本的loadChildren,但这只能在版本9发布之前起作用./p>

这是编译器无法在AOT中使用的版本

  if (this.lazyWidgets.hasOwnProperty(name)) {
      return this.lazyWidgets[name]().then((mod: any) => {
        const moduleFactory = this.compiler.compileModuleSync(mod);
        const entryComponent = (<any>moduleFactory.moduleType).entry;
        const moduleRef = moduleFactory.create(this.injector);
        const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);

        const comp = container.createComponent(compFactory);
        (<WidgetComponent>comp.instance).widget = widget;
        const personalize = (<any>moduleFactory.moduleType).personalize;
        if (personalize) {
          return {
            instance: <WidgetComponent>comp.instance,
            personlize: {
              comp: personalize,
              factory: moduleRef.componentFactoryResolver,
              injector: moduleRef.injector
            }
          };
        }
 

这是我正在考虑如何执行但又无法将其添加到ViewContainerRef的示例.

模块实例实现了一个需要"entry"属性的接口.

这定义了要加载的实际组件:

   if (this.lazyWidgets.hasOwnProperty(name)) {
      return this.lazyWidgets[name]().then((mod: any) => {

        const comp = mod.entry;
        (<WidgetComponent>comp.instance).widget = widget;
        const personalize = mod.personalize;
        if (personalize) {
          return {
            instance: <WidgetComponent>comp.instance,
            personlize: {
              comp: personalize,
               factory: null //this no longer works:  moduleRef.componentFactoryResolver,
              // injector: moduleRef.injector
            }
          };
        } else {
          return {
            instance: <WidgetComponent>comp.instance
          };
        }
      });
    } 

 

我试图在stackblitz中添加一个示例,但是编译器正在将我的字符串转换为函数.至少代码更具可读性.这是我在angular 8中所做的.我基本上需要一种方法来使用import()而不是魔术弦.

https://stackblitz.com/edit/angular-9yaj4l

解决方案

在Angular 8中,loadChildren函数的结果在JIT模式下为NgModule类型的Promise或在AOT中为NgModuleFactory类型的Promise模式.

考虑到这一点,您可以按以下方式重写服务:

import { 
    Injectable, Compiler, Injector, Type, 
    ViewContainerRef, ComponentFactoryResolver,
    NgModuleFactory, Inject 
} from '@angular/core';

@Injectable()
export class LazyLoaderService {

  constructor(private injector: Injector,
    private compiler: Compiler,
    @Inject(LAZY_WIDGETS) private lazyWidgets: 
       { [key: string]: () => Promise<NgModuleFactory<any> | Type<any>> }) { }


  async load(name: string, container: ViewContainerRef) {
    const ngModuleOrNgModuleFactory = await this.lazyWidgets[name]();
 
    let moduleFactory;

    if (ngModuleOrNgModuleFactory instanceof NgModuleFactory) {
      // aot mode
      moduleFactory = ngModuleOrNgModuleFactory;
    } else {
      // jit mode
      moduleFactory = await this.compiler.compileModuleAsync(ngModuleOrNgModuleFactory);
    }

    const entryComponent = (<any>moduleFactory.moduleType).entry;
    const moduleRef = moduleFactory.create(this.injector);

    const compFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(entryComponent);

    const comp = container.createComponent(compFactory);
  }   
}

Stackblitz示例

提示: 如有疑问,请始终查看源代码

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