DEV Community

Anirban Mukherjee
Anirban Mukherjee

Posted on • Updated on • Originally published at theangularpath.anirbanblogs.com

Angular dynamic components with code-splitting

GitHub logo 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.

CMS content layout

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.

Lazy loading
Lazy Loading
 

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:

Sample CMS Data
Customer Code

Now, let's take a look at the custom structural directive:
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.

tsconfig.app.json


Cheers!
Anirban Mukherjee

Top comments (0)