Lazy loading and providers

Hi,

Right now, while using lazy loading, I load all my providers in app.module.ts which I guess isn’t maybe the best strategy because this won’t speed up my app boot time, specially because I’ve got something like 50 custom providers (don’t judge me :wink: ).

Therefore I’m asking my self if I should really load all of them for my all app or if I should load them only where I only use them? How are you guyz solving this?

Furthermore, in case I should better not load them for the all app, it’s not clear for me all to solve following:

Let say I’ve got three pages (A,B and C) with their own modules and three providers (1,2 and 3).

A use 1
B use 1, 2, 3
C use 1, 2

I guess, since 1 is use across all the app, I would have to declare it in app.module.ts
Since 3 is only use in page B, I guess I would have to only declare it in B.module.ts

But what about 2. How could I declare it in both B.module.ts and C.module.ts with the goal to share the same provider “memory” (if the provider contains a value, both B and C should see the same object), respectively how I would code that? Simply by injecting the provider “as usual” and angular do the rest?

Thx in advance for any help, would really be appreciated

4 Likes

I don’t have an answer for you, but I thought you might like to know that I’m struggling with exactly the same decisions. I have some providers that only inject into exactly one place – often another provider, which I broke into sub-providers to modularize code. And I’m not sure what the best way to handle this is. I want a unique global state, but I also want as little loaded up front as possible.

1 Like

Thx feel a bit less alone :wink:

I’m guessing not loading all these providers would really improve my boot time but I’ve really no idea if it’s possible to share a provider between only a selected list of modules, which would be a must in my case, but I’ve got really no idea if it’s possible and if yes, really no idea how to code it :frowning:

Forwarded my question to stackoverflow too:

@AaronSterling don’t know if you would be agree with me but I just read the angular documentation and I have the feeling that this is a design restriction respectively angular is designed to load all providers at boot time without any other pattern. Do you understand this the same way as I do?

https://angular.io/guide/ngmodule-faq#q-component-scoped-providers

No, just a little further down there’s this.
https://angular.io/guide/ngmodule-faq#should-i-add-other-providers-to-a-module-or-a-component

I see two issues:
(1) code design: The programmer needs to clearly decide which providers are universal, and which providers are only used by a particular consumer (in a well-understood limited context). Then providers of type 1 are declared in app.module.ts, and providers of type 2 are declared in a local (presumably lazily loaded) module.

(2) Ionic support: Does Ionic lazy loading support this? I don’t know the answer to this question. The official docs seem to say “yes” but it doesn’t seem that simple.

I’m still finalizing (1) in my own project.

1 Like

Thx for pointing that out, don’t know why but I’m really confuse about this subject…I should do more test locally to see what works and what doesn’t work with my app

Anyway, reading the documentation you pointed out, I found the following super duper important to understand, thx a lot

Then each new instance of the HeroEditorComponent gets its own cached service instance. The changes that editor makes to heroes in its service don’t touch the hero instances elsewhere in the application.

When you’ll have finalized (1) in your project, if you would have time to share a feedback or piece of code, I would love to read that…but like I said, if you’ve got time, no pression at all :wink:

Hi,

If you are using lazy loading module for your pages (A, B, C), then just add your provider name under providers:[] property in @NgModule of each pages.

B.module.ts

import { Provider2 } from '../provider2';
@NgModule({
  ...
  providers: [
    Provider2
  ]
})
export class B {}

C.module.ts

import { Provider2 } from '../provider2';
@NgModule({
  ...
  providers: [
    Provider2
  ]
})
export class C {}

Alternatively, register at a component level in the providers property of the @Component metadata:

@Component({
  selector:    'app-hero-list',
  templateUrl: './hero-list.component.html',
  providers:  [ HeroService ]
})

https://angular.io/guide/architecture#dependency-injection

2 Likes

See Learn Multiple File Upload by building an Instragram-style app

and @rlouie view on local declaration of providers.

Some say Ionic Apps are so small, you only want to declare in module.

Regards

Tom

I did forget about this thread

So I gonna close it and mark the answer of @AaronSterling as the correct one

If I understand correctly

a. You use stateless providers, then yes you might be able to declare them in separate modules because if you do so, each modules gonna use is own provider (“no memory share between mutliple instance of the same provider”)

b. Your providers aren’t stateless, for example you use them to keep values in memory, then they have to be only declared once for the all app respectively in app.module.ts

@Tommertom If your app is quite small then yes it is easy to code without following any design patterns, there’s a low chance of getting confused and you don’t need lazy loading.

Services provided in components can still share their state with any child components, that’s why angular best practices state you should provide services from the top-most component from where they will be shared. While it’s true you could provide them in a module, it’s a design practice to keep your code where it’s relevant.

If your service is only used by a component and it’s children, you should only provide it there. Now your code is local to where it’s used. It’s also worth noting that a service provided in a module is a singleton for your entire application unless that module is lazy loaded. That means if you aren’t lazy-loading your module, it doesn’t matter if you provide your service in app.module.ts or page1.module.ts.

In order to prevent app.module from becoming 200 lines of service providing, the best practice guide also recommends putting any services that need to share data across your whole app into a core feature module. You’ll then know that anything in there shares data across your whole app.

Also remember that presently Ionic doesn’t really have proper support for modular code lazy-loading, something I’ve complained about in the past. However, their latest blog post says they are going to start using the Angular router and the Angular CLI. This means for the first time in Ionic you’ll be able to truly make modular code where features are wholly contained in easily reusable and lazy-loadable modules.

So if you were making a user-admin feature for your app you might have a directory structure like this:

/user-admin
  user-admin.module.ts
  user-admin.component.ts
  user-admin.component.html
  user-admin.component.scss
  user-admin.service.ts
  user-admin.routing-module.ts
  user.component.ts

This single folder contains a module that provides a user-admin service that talks to your server, a component that represents a single user, and then a main user-admin component that lists out all your users. Not only can all of this code be lazily loaded, the components, the service, even the css (where previously Ionic only supported page component and html lazy-loading), it’s also super easy to reuse this code.

If another app needs user admin, simply copy-paste this folder into your app and import the user-admin.module. That’s it, it will work.

This entire feature is also now self contained, so it’s very clear that the user-admin.service is only used in the user-admin component and it’s child user component, so you can provide it from the user-admin component.

3 Likes

this sentence sounds like a good summary to keep in mind to me, thx