Angular 6+ complete dependency deployment guide. providedIn vs providers:[]

Angular 6+ complete dependency deployment guide. providedIn vs providers:[] 3r3609.  3r3619. 3r3609.  3r3619. In Angular ? a new improved syntax has appeared for injecting service dependencies into the application (3r-3589. ProvideIn 3r-3590.). Despite the fact that Angular 7 has already been released, this topic is still relevant. 3r3-3589. There is a lot of confusion in GitHub, Slack and Stack Overflow comments, so let's take a closer look at this topic. 3r3609.  3r3619. 3r33590. 3r3609.  3r3619. 3r3599. In this article we will look at: 3r30000. 3r3609.  3r3619. 1. The introduction of dependencies (3r3-389. Dependency injection 3r3- 3590.); 3r3609.  3r3619. 2. The old way of introducing dependencies into Angular (3r3-3589. Providers:[]3r3-39090.); 3r3609.  3r3619. 3. A new way to add dependencies to Angular (3r3-3598. ProvidedIn: 'root' | SomeModule [/b] ); 3r3609.  3r3619. 4. Scenarios for using r3-33589. provideIn 3r33590. ; 3r3609.  3r3619. 5. Recommendations for the use of new syntax in applications; 3r3609.  3r3619. 6. To summarize. 3r3609.  3r3619. Angular documentation. 3r362. 3r3609.  3r3619. Formal explanations are good, but let's take a closer look at what dependency injection is. 3r3609.  3r3619. 3r3609.  3r3619. All components and services are classes. Each class has a special method 3r3-3589. constructor [/b] , which, when called, creates an instance object of this class that is used in the application. 3r3609.  3r3619. 3r3609.  3r3619. Suppose one of our services has the following code:
 3r3619. 3r3609.  3r3619.
3r3104. constructor (private http: HttpClient)
3r3609.  3r3619. If you create it without using the dependency injection mechanism, you need to add 3r33589. HttpClient [/b] manually. Then the code will look like this:
 3r3619. 3r3609.  3r3619.
3r3104. const myService = new MyService (httpClient)
3r3609.  3r3619. But from where in this case take httpClient ? You must create one too: 3r3609.  3r3619. 3r3609.  3r3619.
3r3104. const httpClient = new HttpClient (httpHandler)
3r3609.  3r3619. But where do you get now? httpHandler ? And so on, until instances of all necessary classes are created. As we can see, manual creation can be complicated and errors can occur in the process. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. Angular's dependency injection mechanism does it all automatically. All we have to do is specify the dependencies in the component constructor, and they will be added without any effort on our part. 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. 3r3599. The old way of integrating dependencies into Angular (providers:[]) Is
3r3609.  3r3619. To run the application, Angular needs to know about each individual object that we want to embed in components and services. Prior to the release of Angular ? the only way to do this was to specify the services in the 3r3-33589 property. providers:[]3r33590. decorators @NgModule , 3r???. @ Сomponent [/b] and 3r33589. @Directive [/b] . 3r3609.  3r3619. 3r3609.  3r3619. Let us examine three main cases of using 3r3-35899. providers:[]3r33590. :
 3r3619. 1. In the decorator @NgModule immediately loadable module (3r3-3899. eager 3r33590.); 3r3609.  3r3619. 2. In the decorator @NgModule a module with delayed loading (3r3-3589. lazy 3r3-3590.); 3r3609.  3r3619. 3. In decorators 3r3-3899. @ Сomponent [/b] and 3r33589. @Directive [/b] . 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. Modules loaded with the application (Eager) 3r33535. 3r3609.  3r3619. In this case, the service is registered in the global scope as a singleton. He will be a singleton even if it is included in 3r-33589. providers[]3r33590. multiple modules. A single instance of the service class is created, which will be registered at the root level of the application. 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. Modules with delayed loading (Lazy) 3r33535. 3r3609.  3r3619. The instance of the service connected to 3r3353589. lazy [/b] module will be created during its initialization. Adding such a service to the 3-333589 component. eager 3r33590. module will result in an error: 3r3-3899. No provider for MyService! error [/b] . 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. Implementation in @ Сomponent and @Directive
3r3609.  3r3619. When implemented in a component or a directive, a separate instance of the service is created, which will be available in this component and all its children. 3r3-3589. In this situation, the service will not be a singleton; its instance will be created each time the component is used and deleted along with the removal of the component from the DOM. 3r33590. 3r3609.  3r3619. 3r3194. 3r3609.  3r3619. In this case, 3r3-3899. RandomService [/b] not implemented at module level and not singlton,
 3r3619. And registered in 3r???. providers:[]3r33590. component 3r3589. RandomComponent [/b] . As a result, we will get a new random number each time you use 3r33589.
3r33590. . 3r3609.  3r3619. 3r3609.  3r3619. 3r3599. New way to embed dependencies in Angular (providedIn: 'root' | SomeModule) 3r33600. 3r3609.  3r3619. In Angular ? we got the tool. “Tree-shakable providers” 3r33590. to embed dependencies in an application that can be used using the 3r3-3589 property. providedIn 3r3-3590. decorator @Injectable . 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. You can imagine 3r33589. providedIn 3r3-3590. as dependency injection in the opposite direction: earlier, the module described the services to which it will be connected, now the service determines the module to which it is connected. 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. The service can be embedded in the application root (3r3-3598. ProvidedIn: 'root' 3r?590.) Or in any module (3r?589. ProvidedIn: SomeModule ). 3r3-3589. providedIn: 'root' [/b] is an abbreviation for implementation in 3r3-3899. AppModule [/b] . 3r3609.  3r3619. 3r3609.  3r3619. Let us analyze the main scenarios for using the new syntax:
 3r3619. 1. Embedding into the root module of the application (3r3-3589. ProvidedIn: 'root' 3r?53590.); 3r3609.  3r3619. 2. Implementing an immediately loadable module (3r33589. Eager 3r33590.); 3r3609.  3r3619. 3. The introduction of the module with deferred loading (3r33589. Lazy 3r33590.). 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. Embedding into the root module of the application (providedIn: 'root') 3r3-33535. 3r3609.  3r3619. This is the most common version of dependency injection. In this case, the service will be added to the bundle application only if it is actually used, i.e. embedded in a component or other service. 3r3609.  3r3619. 3r3609.  3r3619. When using the new approach, there will not be much difference in the monolithic SPA application, where all the written services are used, however, 3r-3589. providedIn: 'root' [/b] will be useful when writing libraries. 3r3609.  3r3619. 3r3609.  3r3619. Previously, all library services needed to be added to 3r33589. providers:[]3r33590. its module. After the library was imported into the application, all services were added to the bundle, even if only one was used. In the case of 3r???. providedIn: 'root' [/b] No need to connect the library module. Simply implement the service in the desired component. 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. The module is deferred loading (lazy) and providedIn: ‘root’ 3r-33535. 3r3609.  3r3619. What happens if you implement a service from 3r33535. providedIn: 'root' [/b] in 3r3-3589. lazy [/b] module? 3r3609.  3r3619. 3r3609.  3r3619. Technically 3r3-3589. 'root' [/b] is AppModule , but Angular is smart enough to add a service to the bundle. lazy module, if it is embedded only in its components and services. But there is one problem (although some people claim that this is a feature). If later to introduce the service used only in 3r3-3589. lazy [/b] module, in the main module, the service will be transferred to the main bundle. In large applications with many modules and services, this can lead to problems with dependency tracking and unpredictable behavior. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. Be careful! The introduction of one service in a variety of modules can lead to hidden dependencies that are difficult to understand and impossible to unravel. 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. Fortunately, there are ways to prevent this, and we’ll look at them below. 3r3609.  3r3619. 3r3609.  3r3619. 3r3599. Dependency injection into an immediately loadable module (eager) 3r33600. 3r3609.  3r3619. As a rule, this case does not make sense and we can use 3r3-3589 instead. providedIn: 'root' [/b] . Connection service in 3r33589. EagerModule [/b] can be used to encapsulate and prevent deployment without plugging in a module, but in most cases there is no such need. 3r3609.  3r3619. 3r3609.  3r3619. If you really need to limit the scope of the service, it is easier to use the old method 3r-3589. providers:[]3r33590. , as it does not exactly lead to circular dependencies. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. If possible, try to use providedIn: 'root' in all eager modules. 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. Note. The advantage of modules with delayed loading (lazy)
3r3609.  3r3619. One of the main features of Angular is the ability to easily break the application into fragments, which provides the following advantages:
 3r3619. 1. The small size of the main application bundle, which is why the application loads and starts faster; 3r3609.  3r3619. 2. The module with delayed loading is well isolated and is connected in the application once in the property 3r-3589. loadChildren [/b] corresponding route. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. Due to deferred loading, a whole module with hundreds of services and components can be deleted or put into a separate application or library without much effort. 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. Another advantage of isolation is 3r3–3589. lazy [/b] The module is that the error made in it will not affect the rest of the application. Now you can sleep well even on the day of release. 3r3609.  3r3619. 3r3609.  3r3619. 3r3599. Implementing a delayed load module (providedIn: LazyModule) 3r33600. 3r3609.  3r3619. 3r3609.  3r3619. The implementation of dependencies in a specific module does not allow using the service in the rest of the application. This allows you to maintain the structure of dependencies, which is especially useful for large applications in which indiscriminate dependency injection can lead to confusion. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. Interesting fact: If the lazy service is implemented into the main part of the application, then the assembly (even the AOT) will pass without errors, but the application will fall with the error "No provider for LazyService". 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. The problem with the cyclic dependence 3r33535. 3r3609.  3r3619. 3r3609.  3r3619. You can reproduce the error as follows:
 3r3619. 1. Create a module. LazyModule ; 3r3609.  3r3619. 2. We create service LazyService and connect using providedIn: LazyModule ; 3r3609.  3r3619. 3. Create a 3r3-3899 component. LazyComponent [/b] and connect to r3r3589. LazyModule [/b] ; 3r3609.  3r3619. 4. Add LazyService in the constructor component LazyComponent ; 3r3609.  3r3619. 5. We get an error with a cyclic dependence. 3r3609.  3r3619. 3r3609.  3r3619. Schematically, it looks like this: service -> module -> component -> service . 3r3609.  3r3619. 3r3609.  3r3619. You can solve this problem by creating a sub-module 3r3-3589. LazyServiceModule [/b] which will be connected in LazyModule . To connect the submodule services. 3r3609.  3r3619. 3r3609.  3r3619. 3r3609.  3r3619. In this case, you will have to create an additional module, but this does not require much effort and will provide the following advantages:
 3r3619. 1. Prevent the implementation of the service in other application modules; 3r3609.  3r3619. 2. The service will be added to the bundle only if it is embedded in the component or another service used in the module. 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. Implementing a service in a component (providedIn: SomeComponent) 3r3-33535. 3r3609.  3r3619. Is it possible to implement the service in 3r33589. @ Сomponent [/b] or @Directive using the new syntax? 3r3609.  3r3619.3r3609.  3r3619. 3r3-3589. Not at the moment! 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. To create a service instance for each component, it is still necessary to use 3r33589. providers:[]3r33590. in decorators 3-333589. @ Сomponent [/b] or @Directive . 3r3609.  3r3619. 3r3609.  3r3619. 3r3609.  3r3619. 3r3599. Recommendations for using the new syntax in applications 3-333600. 3r3609.  3r3619. 3r? 3534. Libraries 3r33535. 3r3609.  3r3619. 3r3-3589. providedIn: 'root' [/b] Good for creating libraries. This is really a convenient way to plug into the main application only the directly used part of the functionality and reduce the size of the final assembly. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. One practical example is the 3r3493 library. ngx-model
which was rewritten using the new syntax and is now called @ angular-extensions /model . In the new implementation there is no need to connect the NgxModelModule to the application, it is enough just to embed the ModelFactory into the required component. Implementation details can be viewed here 3r3612. . 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. Modules with delayed loading (lazy) 3r33535. 3r3609.  3r3619. Use for services separate module providedIn: LazyServicesModule and connect it to LazyModule . This approach encapsulates services and will not allow them to be connected to other modules. This will mark the boundaries and help create a scalable architecture. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. In my experience, accidental embedding into a main or additional module (using providedIn: 'root') can be confusing and is not the best solution! 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. 3r3-3589. providedIn: 'root' [/b] will also work correctly, but when using 3r3-3589. providedIn: LazyServideModule [/b] we get error "Missing provider" when implemented in other modules and we can fix the architecture. 3r3-3589. Move the service to a more suitable place in the main part of the application. 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. 3r? 3534. In which cases it is worth using providers:[]? 3r33535. 3r3609.  3r3619. In cases when it is necessary to configure the module. For example, connect the service only SomeModule.forRoot (someConfig) . 3r3609.  3r3619. 3r33542. 3r3609.  3r3619. 3r3-3589. On the other hand, in such a situation, you can use providedIn: 'root'. This will ensure that the service will be added to the application only once. 3r33590. 3r3609.  3r3619. 3r3609.  3r3619. 3r3599. Conclusions 3r3600. 3r3609.  3r3619. 1. Use 3r???. providedIn: 'root' [/b] to register the service as a singleton, available throughout the application; 3r3609.  3r3619. 3r3609.  3r3619. 2. For the module included in the main bundle, use 3r33589. providedIn: 'root' [/b] , but not providedIn: EagerlyImportedModule . In exceptional cases, use 3r3-3589 to encapsulate. providers:[]3r33590. ; 3r3609.  3r3619. 3r3609.  3r3619. 3. Create a sub-module with services to limit their scope 3r3-3589. providedIn: LazyServiceModule [/b] when using deferred loading; 3r3609.  3r3619. 3r3609.  3r3619. 4. Connect the module. LazyServiceModule in 3r3-3589. LazyModule [/b] to prevent cyclic dependencies 3r3609.  3r3619. 3r3609.  3r3619. 5. Use 3r???. providers:[]3r33590. in decorators 3-333589. @ Сomponent [/b] and 3r33589. @Directive [/b] to create a new service instance for each new component instance. The service instance will also be available in all child components; 3r3609.  3r3619. 3r3609.  3r3619. 6. Always limit dependency areas to improve architecture and avoid confusing dependencies. 3r3609.  3r3619. 3r3609.  3r3619. 3r3599. References
3r3609.  3r3619.
Original article. 3r3612. 3r3609.  3r3619.
Angular - Russian-speaking community. 3r3612. 3r3609.  3r3619. 3r3611. Angular Meetups in Russia
3r3620. 3r3619. 3r3619. 3r3619. 3r31717. ! function (e) {function t (t, n) {if (! (n in e)) {for (var, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d ): d ()}}} t ("//"""_mediator") () (); 3r3618. 3r3619. 3r3620.
+ 0 -

Add comment