The Need for Speed: Lazy Load Non-Routable Modules in Angular ????Netanel BasalBlockedUnblockFollowFollowingFeb 5As you probably know, Angular comes with a functionality that allows you to lazy load routable modules out of the box.
Although in most cases this functionality is sufficient, it’s still only a small piece of the pie.
What about situations where we want to lazy load modules that aren’t routable?We can study one real-world case like this from our application.
We have a page that displays a list of widgets.
Each widget comes with a settings button that, when clicked, opens a side panel and allows the user to customize the widget’ settings.
The widget settings panel contains a world of components, directives, pipes, and providers.
It would be a waste to add the module to our main bundle, because then all clients would have to download and parse it, even though most would probably never use it.
A better decision would be to lazy load the module when the user clicks on the edit settings button.
Let’s learn how can we do that.
First, we need to create the module:We created a WidgetSettingsModule and provided it with everything it needs (i.
, components, directives, etc.
Our next step is to instruct Angular to ask Webpack to create a separate chunk for our module so we can lazy load it later on.
We can do this by adding the module path to the angular.
json file:Great, now we can see that Webpack extracts our module, with all of its dependencies, to a separate chunk.
Next, we need “something” that knows how to load our modules.
We can learn from the router itself and use the SystemJsNgModuleLoader loader.
Let’s declare it in our AppModule:To load the module, we’ll use a custom directive that takes the module name as input, then loads the module and injects the root component to the current ViewContainerRef.
Here’s an example of the final result:First, let’s create a provider that holds the lazy load modules map:Now, we can build the final piece in the puzzle — the directive:We inject the loader provider and call the load() method passing the module path that we grab from the LAZY_MODULES_MAP injection token.
If we take a look at the source code we’ll see that the load() method uses SystemJS to load and compile the module.
Then, it returns the result, an object of type NgModuleFactory.
A bit of advice — try to always understand how things work under the hood.
Ok, we have a module factory, now we need to create an instance of it.
We call the create() method passing the current injector, and we get a reference to the module.
At this stage, we have a module, but we still need to create the root component and inject it to the view.
How do we do that?Our first option would be to add it to the module’s bootstrap property:And then get it from the moduleRef:But I don’t like to use a private API, as it might be changed.
I mean, there is a reason it’s private, right?.Instead, I recommend storing the root component in a static property on the module itself:And get it from the moduleFactory:Finally, let’s get the component factory and create the component:And let’s not forget to destroy the module:And really, that’s all there is to it.
Here’s a live AOT example:????.Last but Not Least, Have you Heard of Akita?Akita is a state management pattern that we’ve developed here in Datorama.
It’s been successfully used in a big data production environment, and we’re continually adding features to it.
Akita encourages simplicity.
It saves you the hassle of creating boilerplate code and offers powerful tools with a moderate learning curve, suitable for both experienced and inexperienced developers alike.
I highly recommend checking it out.
????.Introducing Akita: A New State Management Pattern for Angular ApplicationsEvery developer knows state management is difficult.
Continuously keeping track of what has been updated, why, and…netbasal.
comFollow me on Medium or Twitter to read more about Angular, Akita and JS!.. More details