What is SharedModule
anyway?
To set up some context for this post, here’s a typical SharedModule
Or more than often, we usually have a SharedModule
for re-exporting 3rd party Modules
With this in place, we can import SharedMaterialModule
to have access to MatButtonModule
, MatTableModule
, and MatCardModule
.
Now that we have an idea of what SharedModule
is, let’s explore why SharedModule
is not as clever as we thought it would be.
Scenario 1: Internal SharedModule
Problem
- Lazy-load
FooModule
- Lazy-load
BarModule
SharedModule
declaresSharedAComponent
andSharedBComponent
FooModule
usesSharedAComponent
by importingSharedModule
BarModule
usesSharedBComponent
by importingSharedModule
A screenshot showing bundlesize of FooModule, BarModule, and SharedModule
From Screenshot 1, we can see that SharedModule
is separated into its own chunk. This makes the size of FooModule
and BarModule
small, which appears to be a good thing.
However, both FooModule
and BarModule
are lazy-loaded modules. It means, in practice, our users might land only on FooModule
(eg: /foo
) and never need to load BarModule
(and vice versa).
When we load either FooModule
or BarModule
, we load SharedModule
.
Why is this a bad thing? Because FooModule
only uses SharedAComponent
, but we also load SharedBComponent
since we load the whole SharedModule
.
This is wasted! Imagine having EVERY shared components in SharedModule
, that would be a huge waste. In other words, it kind of defeats the purpose of your lazy-loaded modules in my opinion.
Solution
The easiest solution is to apply Single-Component-as-Module (or SCAM) here for SharedAComponent
and SharedBComponent
. Learn more about SCAM
A screenshot showing bundlesize of FooModule, BarModule, with two SCAMs
After we apply SCAM to the two shared components, we will end up with Screenshot 2. FooModule
bundle size is getting slightly larger because SharedAModule
is bundled together with it (the same applies to BarModule
and SharedBModule
).
However, when our users land on FooModule
, we will truly only load what the users actually need: FooModule
and SharedAComponent
without loading the unnecessary SharedBComponent
Scenario 2: External modules
This scenario is somewhat out of our control but we will explore it as well.
- Only
FooModule
utilizesFormsModule
- Both
FooModule
andBarModule
utilizeFormsModule
A screenshot showing bundlesize of FooModule and FormsModule
A screenshot showing bundlesize of FooModule, BarModule, and FormsModule
Here, you can see that if only FooModule
needs FormsModule
, then Angular will know to include FormsModule
together with FooModule
bundle, so that if our users land on BarModule
, we don’t need to load FormsModule
for them. (Screenshot 3)
On the other hand, if both FooModule
and BarModule
need FormsModule
, then Angular will separate FormsModule
into a common chunk so FormsModule
is only loaded once. (Screenshot 4)
Conclusion
Main take-away is that Angular is smart enough to help you enhance the users’ experience with your application. Embrace Single-Component-as-Module, you’ll only pay for what you (or your users) need.Main take-away is that Angular is smart enough to help you enhance the users’ experience with your application. Embrace Single-Component-as-Module, you’ll only pay for what you (or your users) need.