Lars
Lars

Reputation: 1092

Angular lazy load module that only contains services?

I'm looking for a way to lazy load a module that doesn't contains any components but services only. The background: in my app is an Excel export service using exceljs library. This library is extremely large and I'm trying to prevent that the library will become part of vendor.js or main.js. It is "included" via import * as Excel from 'exceljs/dist/exceljs.min.js' in a service.

Now I have several components in separate modules that make use of the "Excel export" service (no component). I would prefer a method that the service is only loaded if the user is "clicking the export button" but not before.

How this can be done?

Upvotes: 1

Views: 921

Answers (1)

Andrei Gătej
Andrei Gătej

Reputation: 11979

Here would be an approach:

excel.module.ts

@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ],
  providers: [ExcelService]
})
export class ExcelModule {
  static loaded = false;
}

app.component.ts

export class AppComponent {
  constructor (
    private compiler: Compiler,
    private injector: Injector
  ) { }
  
  load () {
    import('./excel/excel.module')
      .then(m => m.ExcelModule)
      .then(m => {
        console.dir(m.loaded)
        
        return m;
      })
      .then(m => this.compiler.compileModuleAsync(m).then(r => (m.loaded = true,r)))
      .then(factory => {
        const module = factory.create(this.injector);
        
        console.dir(module.injector.get(ExcelService))
      })
  }
}

The first time is loaded, m.loaded will be false. On subsequent times, it will be true. With this, we can be sure that we don't load the module multiple times.

Of course, a easier (and probably better) approach will be to have a dedicated service for loading modules e.g ModuleLoaderService, where you'd have a Map object keeping track of loaded modules.

ng-run demo.

Upvotes: 1

Related Questions