简体   繁体   中英

Angular 8 CLI: How to lazy load non-routable feature module with providers

So hey,

I tried to follow these guides: https://angular.io/guide/lazy-loading-ngmodules

But the official documentation only covers this with Router (just wow. Qngular docs are suboptimal)

https://netbasal.com/the-need-for-speed-lazy-load-non-routable-modules-in-angular-30c8f1c33093

So this medium article was exactly what I was searching for. My only problem is that it wont work.

ANGULAR.JSON

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "lazyModules": [
              "path/to/components#MyModule"
            ],

APP MODULE

 providers: [
    SystemJsNgModuleLoader, // without this I get NullInjectorError
    CookieService,
    { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }, // this doesnt seem to do anything
    {
      provide: HTTP_INTERCEPTORS, useClass: AuthHeaderInterceptor, multi: true,
    }
  ],
  bootstrap: [AppComponent]

MODULE

@NgModule({
  imports: [
    CommonModule,
    MatButtonModule,
    MatIconModule,
  ],
  declarations: [
    MyModule.rootComponent
  ],
  providers: [MyService],
  entryComponents: [MyModule.rootComponent]
})
export class MyModule{
  static rootComponent = MyComponent;
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: MyModule,
      providers: [MyService]
    };
  }
}

SERVICE

@Injectable()
export default class MyService {}
...

LAZY LOAD PROVIDER

export interface LAZY_MODULES {
  'MyModule': string;
}

export const lazyMap: LAZY_MODULES = {
  'MyModule': 'path/to/components#MyModule'
};

export const LAZY_MODULES_MAP = new InjectionToken('LAZY_MODULES_MAP', {
  factory: () => lazyMap
})

LAZY LOAD DIRECTIVE

@Directive({
  selector: '[lazyLoadModule]'
})
export class LazyLoadModuleDirective implements OnInit, OnDestroy {

  @Input('lazyLoadModule') moduleName: keyof LAZY_MODULES;
  private moduleRef: NgModuleRef<any>;

  constructor(
    private vcr: ViewContainerRef,
    private injector: Injector,
    private loader: NgModuleFactoryLoader,
    @Inject(LAZY_MODULES_MAP) private modulesMap
  ) { }

  ngOnInit() {
    this.loader
      .load(this.modulesMap[this.moduleName])
      .then((moduleFactory: NgModuleFactory<any>) => {
        this.moduleRef = moduleFactory.create(this.injector);
        const rootComponent = (moduleFactory.moduleType as ModuleWithRoot)
          .rootComponent;

        const factory = this.moduleRef.componentFactoryResolver.resolveComponentFactory(
          rootComponent
        );

        this.vcr.createComponent(factory);
      });
  }

  ngOnDestroy() {
    this.moduleRef && this.moduleRef.destroy();
  }
}

IN APP COMPONENT HTML

<ng-container *ngIf="showModule"
              lazyLoadModule="MyModule">
</ng-container>

so the result is:

  1. If I am using th SystemJsNgModuleLoader without wrapper object, Chunking works (webpack reports that it build a path-to-components-my-module.ts ) In dev tools I get NullinjectorError for SystemJsNgModuleLoader

  2. If I am using the SystemJsNgModuleLoader directly in providers I dont get an error in dev console. Chunking works also. But in network console, the module never gets loaded , even if i directly set showModule=true in app controller...

The above example worked. The guide was trivially assuming that everyone remembers to add the loader component the root module.

Interestingly no error was thrown, (because it is a directive, not an element) and the system just assumed that lazyLoadModule is a permitted HTML attribute? ANyway fixed by:

@NgModule({
  declarations: [
    ...,
    LazyLoadModuleDirective
  ]
  ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM