Are you strugging to lazy load Angular components into your CMS platform or any other Non-Angular project? Then this article is for you!
I have been working with Adobe Experience Manager (AEM) for almost two years and most of the time I combined it with Angular as a frontend framework. One of my first tasks as an AEM developer was to find a good way to use Angular in conjunction with the CMS platform.
At the time, Angular 6 had just been released and one of its main new features was Angular Elements. Angular Elements allows to create Web Components from Angular components and reuse them in other applications using different technologies. Since Web Components are framework agnostic and self-bootstrapped they are great for dynamic sites with CMS platforms.
There are some articles you can read about Angular Elements:
One of the good things of Web Components and custom elements is that you import some JS and CSS and you are ready to use them. With Angular you can
run ng build --prod and import the generated bundle files in other applications to use your custom elements.
Also you can use ngx-build-plus to build your custom elements. With this library you can get a single bundle file when building your project with Angular CLI.
Despite there are use cases where it could be handy to have all the components bundled to a single or a few files -like design systems-, there are other cases where it is not ideal.
In my particular case I have an Angular project with about 20 -big- components that are included as custom elements in a dynamic site powered by Adobe Experience Manager. But, only one or two of those components are included in each page.
Code splitting and lazy loading would help to tackle that problem. You can split your application into multiple NgModules accordingly.
In my case, I could split up my project by creating a separate NgModule for each of my components and one or more shared modules to share features across the whole project. Now I would only need to lazy load them in order to lazy load my components.
There are several options to lazy load components in Angular, for example:
But, how to lazy load the components from Non-Angular applications?
With ngx-element you can lazy load your Angular components from everywhere. That means from a CMS platform, a React application or just a plain HTML.
The library will define a custom element which you can pass a selector attribute to. That selector attribute determines what component you want to load. Also you can pass in attributes to your component by setting data-attributes to the custom element.
Credits: Thanks to Juri Strumpflohner for the inspiration with ngx-lazy-el!
Let’s create a small Angular application to see ngx-element in action :) I am using Angular CLI v9.0.6. Choose SCSS as the css preprocessor.
$ ng new lazy-components --minimal $ cd lazy-components
We can remove
app.component.ts since we won’t need it and modify
After doing that our
app.module.ts file should look like this:
Basically I removed the
AppComponent and added the
ngDoBootstrap method since we are not bootsrapping any component in the module.
Now let’s create a Talk component together with its feature module.
$ ng g module talk $ ng g component talk
At the moment you should have the following folder structure:
talk files should look as follow:
Let’s change our
Talk component to make it display some information about a talk in a conference and give it some styles.
talk.component.ts file to the following:
And create the following
talk.component.scss files next to
Until now we have created a component that (trust me) will look like this later:
So nothing strange until now, right? We have created a typical Angular application with an AppModule, a feature module and one component.
Remember that our goal is to use this component in Non-Angular applications and be able to lazy load it. We need Angular Elements and ngx-element in order to do that, so let’s put them in action…
Angular provides a schematic to install and set up Angular Elements in our project. It will add a polyfill but it does not support IE11. If you need IE11 don’t use this schematic and see this article instead.
Install Angular Elements by running
ng add @angular/elements in your terminal.
And install ngx-element by running
npm install ngx-element --save
In order to let ngx-element to access our component and create it on demand we need to make a couple of additions to our
First we need to add
TalkComponent to the
entryComponents array. And second we are going to add a
customElementComponent property to the module in order to make the component’s class accessible to ngx-element.
talk.module.ts should be like this now:
Once we have done this we need to import and configure the
NgxElementModule in our
AppModule as follows:
In order to test our component we are going to create some HTML where we can use it. Remember that we are not bootstrapping any Angular component and we are just adding custom elements to the DOM.
index.html file in the project with the following markup:
And replace the global
styles.scss file with:
At this point, if you run
ng serve in your terminal you should see our component in action:
And you can see that our Talk Module is being lazy loaded as we expected.
Now you can open your DevTools in the Network tab and verify that our
TalkModule is being lazy loaded.
Some things you can play with to see the powers of custom elements:
- Add a new talk to the DOM and see how it is self-bootstrapped.
- Change the
speakerattributes from the DevTools.
- Remove the talk custom elements from
index.htmlfile and verify that the
TalkModuleis not loaded initially. Then add a talk element to the DOM on the fly from the DevTools and verify that the
TalkModuleis lazy loaded.
With ngx-element we have built a component and leveraged all benefits of Angular framework, custom elements and lazy loading.
This library has changed the way I integrate Angular and Adobe Experience Manager for the better. I hope this can be useful for developers trying to use Angular as a frontend framework together with CMS platforms or any other Non-Angular projects.
Thank you for reading 🙂