角度8中的延迟加载模块

Jas*_*son 3 typescript angular

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

我通过定义一个对象来做到这一点{name: string, loadChildren: string}。然后app.module我会做的provideRoutes(...)

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

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

使用,我可以创建一个从模块和调用组件createComponentViewContainerRef

这是该函数:

 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();
      });
    }
Run Code Online (Sandbox Code Playgroud)

在角度8中,loadChildren更改了导入功能。

取而代之的是NgModuleRef实际的模块实例。

我以为我可以通过采用该模块来对其代码进行修复,对其进行编译,以NgModuleRef使其余代码保持不变。

似乎在AOT模式下,尽管编译器未捆绑在一起。

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

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

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

这是带有在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
            }
          };
        }
Run Code Online (Sandbox Code Playgroud)

这是一个我如何考虑但却无法将它添加到的例子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
          };
        }
      });
    } 

Run Code Online (Sandbox Code Playgroud)

编辑:

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

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

yur*_*zui 9

在角8的结果loadChildren函数要么是PromiseNgModule在JIT模式或类型PromiseNgModuleFactory在AOT模式。

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

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);
  }   
}
Run Code Online (Sandbox Code Playgroud)

Stackblitz示例

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