Angular dynamic components with code-splitting
Anirban Mukherjee
Posted on August 3, 2021
anirbmuk / cms-components-demo
Angular 12 application to demonstrate code-splitting
A lot of times, angular components need to be determined and displayed on the fly. A very common use-case is when the components are determined from a content-management-system (CMS). This is particularly useful when we allow the customer to control the content and layout of the page.
Well we do have *ngIf
for that, don't we? Depending on some CMS field value, we can use *ngIf
to determine which component needs to be displayed. This is cool, but there is a major downside to this approach. The problem is, we usually have a large component library, which need to be loaded eagerly in its entirety through one or more modules
. So even if only a fraction of these components may be needed by the customer, we would have to pre-load all of them, which is an unnecessary waste of resources.
So what are we talking about here? How about a way where we load only those components out of our library which are required by the customer? This is where the concept of code-splitting comes into use.
Using code-splitting, we conditionally import the required components at run-time.
The Setup
Let's see how to go about it. I have created a few simple custom angular components, which are to be conditionally loaded. So, as expected, these components are NOT part of any application module.
We need to remember that the entire operation is driven by CMS data. So we need some mechanism to evaluate this data at run-time to determine the components.
So we would need a custom structural directive
for this. This directive would dynamically create the component instances and inject them into the DOM. Let's first look at the HTML needed at the implementation side, using this directive:
Now, let's take a look at the custom structural directive:
The most interesting bit is the import statement (line 25). Based on the CMS content, I only import that particular module and component. This is a huge advantage in terms of app-performance, since we do not have to load a module unless it is explicitly asked for, much like a lazily loaded route! When I place this directive on a designated location in the DOM (the ng-container
in this case), I get access to that location's reference, through ViewContainerRef
. I make use of angular's ComponentFactoryResolver
API to build an instance of our required component and the viewContainerRef injects this component instance at that designated spot.
A small, but very important, GOTCHA!
Since our custom components are not included in any module, or any eager import statements, the angular compiler will exclude these .ts files from compilation. To forcefully compile them, so that they can be used at run-time, we need to tell tsconfig.app.json
to include these files.
Cheers!
Anirban Mukherjee
Posted on August 3, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.