Lazy loading - Providers and modules

I’m moving my app to lazy loading. I’m done with pages, pipes and directives but now it’s the turn of providers/services and some other modules.

This was my app.module:

...
import { FileUploadModule } from "ng2-file-upload";
import { CloudinaryModule } from "@cloudinary/angular-5.x";
import * as cloudinary from "cloudinary-core";
import { ImageUploadProvider } from "../services/image-upload/image-upload";
...
imports: [
 ...
 FileUploadModule,
 CloudinaryModule.forRoot(cloudinary, {
   cloud_name: "cloudName",
   upload_preset: "cloudCode"
  }),
  ...
]
providers: [
 ...
 ImageUploadProvider
  ...
]

Now these references are removed from this file.

I need all of this on my new-recipe component. For that I added this into new-recipe.module:

import { ImageUploadProvider } from "../../services/image-upload/image-upload";
...
providers: [
    ImageUploadProvider
  ]

What else do I need? I also created a image-upload.module but not sure if this is correct:

import { NgModule, ModuleWithProviders } from '@angular/core';
import { FileUploadModule } from "ng2-file-upload";
import { CloudinaryModule } from "@cloudinary/angular-5.x";
import * as cloudinary from "cloudinary-core";
import { ImageUploadProvider } from '../services/image-upload/image-upload';

@NgModule({
  imports: [
    FileUploadModule,
    CloudinaryModule.forRoot(cloudinary, {
      cloud_name: "cloudName",
      upload_preset: "cloudId"
    })
  ],
  exports: [
    CloudinaryModule
  ]
})

export class ImageUploadProviderModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: ImageUploadProviderModule,
      providers: [ImageUploadProvider] // <-- is this necessary?
    };
  }
}

Do I need to import this new module inside new-recipe.module and remove the provider reference? How can I access then from my functions in new-recipe to this.imageUploadProvider?

as far as I know providers are not lazy loadable. You need to import them as normal. If I am wrong - let me know what you did find;)

maybe the provider itself is not prepared to be lazy loaded. That’s why we have to create maybe a shared module. I might be wrong… I’m digging a bit deeper now

so far it works “fine”. The only problem is that it seems to lose some information on next components when I call the properties I changed

See:

I guess you also are risking to create multi tone vs singleton situations…

I’ve read all of that when I initially started with lazy loading here: https://stackoverflow.com/questions/52027735/lazy-loading-and-components/52028175?noredirect=1

But can’t find exactly something to services and shared modules. For example here:
https://angular.io/guide/styleguide#shared-feature-module
they have a .service inside shared folder, but what’s the difference? Are they loading that in app.module or in every component that they need this service?

As I posted I’ve got a shared module for translations but it doesn’t use any provider. You can add providers: [] in this file, in component.module and in component. Where is the correct place? All of them?

@morphist what exactly do you mean? Singletone services have to be inside app.module using forRoot(), right?

See: Angular

Do put a singleton service whose instance will be shared throughout the application in the CoreModule (e.g. ExceptionService and LoggerService ).

See: Angular

Consider not providing services in shared modules. Services are usually singletons that are provided once for the entire application or in a particular feature module.

@NgModule({
  imports: [
    ...
    HttpClientModule,
    IonicModule,
    ServiceWorkerModule.register('/ngsw-worker.js', { enabled: ENV.production }),
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [ HttpClient ]
      }
    })
  ],
  exports: [],
  declarations: [],
  providers: [
    ...
    ENV.production ? { provide: ErrorHandler, useClass: BrewErrorHandler } :
      { provide: ErrorHandler, useClass: IonicErrorHandler},
    { provide: LoggerService, useClass: ConsoleLoggerService }
    ...
  ]
})
export class CoreModule {
  constructor( @Optional() @SkipSelf() parentModule: CoreModule,
               private translate: TranslateService) {

    throwIfAlreadyLoaded(parentModule, 'CoreModule');
    translate.setDefaultLang('en');

    ...
  }
}

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}

I missed that, sorry.

Ok, so core.module is importing some other components and providers. That’s ok, but it’s being imported in app.module. So what is this different from having everything directly on app.module?

In my case I don’t need a core functionality for my provider. My provider/service will be used by some components (not all of them).

About the other options, you said:

Services are usually singletons that are provided once for the entire application or in a particular feature module.

So that means that I don’t need to edit providers: [] inside either modules or components?

Also you suggest me to change my shared module with the translation component to a core module? At the moment I load it on every single .module for my components and the language selection is decided inside app.component

In this example we are loading counter.service in shared.module having SharedModule.forRoot() in app.module. But this is against this right?

Consider not providing services in shared modules

Or this note points to provider: [] inside @NgModule and not inside ModuleWithProviders?

Also, what’s the point of having this if we need to load CounterService on every single component anyway?

At the moment my provider is loaded from different modules and I can use it without problems but when I try to store something this information get reset on the next component. Every module has its own provider. Here I have 2 questions:

  • Does this mean that we need to change the logic to save information and start using different ways like localStorage?
  • If we load this once by component, is not this even worst than a non lazy loading way when it’s being loaded once?