Reputation: 1373
I'm currently beginning with Angular, previously having worked with React.
So far, on other stacks, let's say I write a new file handle-error.js
and selectively import it on a couple of pages, say endpoint1.js
and endpoint2.js
. Given that each of these "endpoints" are defined as entry files on webpack, webpack will usually already work out on how to selectively import this common module handle-error.js
or whether to include it in a commons bundle.
On the other hand, for angular I've seen a couple of common libraries wrapped inside @ngModule classes. So I'm left wondering, what do I lose if I simply import handle-error.js
in my components instead of wrapping it inside an @ngModule?
EDIT:
Let's say I have an app structure like:
|__ base app module
|__ page 1 module
|__ page 2 module
|__ imports handleError() (*)
The documentation clearly states that one main purpose of modules are lazy loading. Since handleError is only required by page 2, wouldnt it only be lazy loaded once page 2 is requested?
Another question would also be: should I also wrap it in a service? Although I already probably know the answer - it helps on mocks for tests.
Upvotes: 1
Views: 94
Reputation: 54811
webpack will usually already work out on how to selectively import this common module handle-error.js or whether to include it in a commons bundle
Yes, that's right and is the same in Angular. Try not to think og NgModules
as having anything to do with webpack bundles. While it's true that a lazy module defined by the router will appear as a separate webpack bundle. This is purely a packaging strategy used by the Angular compiler.
So I'm left wondering, what do I lose if I simply import handle-error.js in my components instead of wrapping it inside an @ngModule?
About 25% of my source code for an Angular project is done like this.
Libraries, extra classes, interfaces, functional programming, utilities and other such things don't need to be in a NgModule
unless you need to use the Angular dependency injector.
The documentation clearly states that one main purpose of modules are lazy loading. Since handleError is only required by page 2, wouldnt it only be lazy loaded once page 2 is requested?
Both Angular and Webpack can not tree shake code based upon dynamic usage. While webpack can tree shake based upon imported usages. It's not able to tell if a global definition of a type was referenced procedurally.
This is particularly difficult in Angular, because of how the dependency injector works.
As a result, think of NgModule
as an upfront way of declaring to Angular what stuff in your project is being used (components, services, providers, etc. etc.).
If no module is referenced by another module, then the entire module can be dropped from the build. Angular has to approach the problem this way, because it uses a run-time dependency injector.
For example;
const thing = injector.get(SOME_UNKNOWN_TOKEN);
In the above example, the dependency token named SOME_UNKNOWN_TOKEN
asks the injector to provide the value for thing
.
Angular has no way of knowing who, what or how SOME_UNKNOWN_TOKEN
was provided. What module it came from, who was responsible for providing it, etc.. etc..
So it can not tree shake based purely on imports. The source code that provides the thing
defined by SOME_UNKNOWN_TOKEN
might not have been imported by anything directly related to the Angular source code (think of third party libraries).
I know this doesn't directly answer your question, but this is why we use modules instead of directly importing things. It would be safe to assume that Angular would be very similar to React in how code is connected if we didn't have the dependency injector.
Another question would also be: should I also wrap it in a service? Although I already probably know the answer - it helps on mocks for tests
It is purely a decision based upon the dependency injector in Angular.
The DI allows you to do a lot of special things that are worth learning, because this is how a lot of component to component connections can be made. Components can also provide their own services and such.
I don't use the DI for complex data structures. Like a tree of object instances or where I need to create many instances of a thing. DI is ideal for single services that depend upon other services.
Upvotes: 1