Micro Front Ends with Angular Elements — Web Components — UPDATED

Hetzel Cordoba
6 min readAug 27, 2019

What’s a Micro Front End?

Most of the projects when start to grow in features, the complexity of the web app begins to rise, and the deploy is taking too much to complete. So to solve of those problems we have to apply a old concept already present in the backend, the micro services.

The majority of the projects in the front end are monolithic, with the Micro Frontend Architecture we divide the web app the different web components, independent of each other, every one with their own development, test and delivery process.

This web architecture is tech agnostic, this means every component can be written using a different framework like Angular o React, enabling multiple teams work in the same project using the technology that suit the best for the component/feature, increasing the browser compatibility, speeding the update, deploy and bug resolving without compromising the main app, and incrementing the component reusability in different projects of the same component.

Facebook use this kind of architecture in his website (see post).

As we can see in the picture above, the chat and news feed are different components in the main window. The main goal is to break the complete website in different web components that don’t affect the user experience, allowing the user to start interacting with the components already loaded.

Creating a Angular Web Component with Ngx-build-plus

Installing Angular Cli

npm install -g @angular/cli

Creating a new project ({project-name}-wc-feature)

ng new phoenix-wc-wiki-ngx

When the terminal ask us to add Would you like to add Angular routing? , we choose No.

We’re going to add the @angular/elements and ngx-build-plus.

ng add @angular/elements

ng add ngx-build-plus

*To check is the installation was successful, go to the angular.json and check the property “builder” under architect → build, should be “builder”: “ngx-build-plus:browser”.

Let’s comment the bootstrap property in the @NgModule declaration`, add the AppComponent to entryComponents, and add the custom element in phoenix-wc-wiki-ngx/src/app/app.module.ts.

*In order to be able to use the AppComponent with ng serve and develop normally, you have to uncomment the bootstrap property in the @NgModule declaration in phoenix-wc-wiki-ngx/src/app/app.module.ts. But not forget to comment it when you are going to generate the build.

Run the command to generate the build.

Run the command to generate the build.

ng build --prod --output-hashing none --single-bundle true

*If you get the following error:

Schema validation failed with the following errors:Data path ".budgets[1].type" should be equal to one of the allowed values.

Go to budgets in the angular.json and delete the lines:

Leaving only:

To test our component, let’s install Static-Server:

npm i -g static-server

In the folder dist/phoenix-wc-wiki-ngx create an index.html, adding the zone.min.js needed to run angular, webcomponents-bundle.js and custom-elements-es5-adapter.js, and polyfill.js to make it cross browser compatible.

Run the command in the folder dist/phoenix-wc-wiki-ngx.

static-server

Go to http://localhost:9080/ and you should see:

Now we make the same process to create another web component called phoenix-wc-wiki-ngx-lt.

Now we have two web components, to test them together , let’s change the of the build files from main-es5.js to{project-name}-bundle.js.

To test both web component working together, let’s add the files *bundle.js to the same folder and change the index.html use for the static-server like this:

Now we make the same process to create another web component called phoenix-wc-wiki-ngx-lt.

Now we have two web components, to test them together , let’s change the of the build files from main-es5.js to{project-name}-bundle.js.

To test both web component working together, let’s add the files *bundle.js to the same folder and change the index.html use for the static-server like this:

f you refresh the http://localhost:9080/ you will see something like:

You can see that now we have both web components in the same page.

Adding initial parameters to the Web Component

Let’s add a web component input parameter to be able to get data from outside for the creation of the web component.

In the src/app/app.component.ts for the phoenix-wc-wiki-ngx-lt project we’re going to add and input element called token, with that we have to add the functions ngOnInit and ngOnChanges in order to handle in incoming data:

After we generate the build we can add the new value to the declaration of the web component.

<phoenix-wc-wiki-ngx-lt token="tokenValueTest"></phoenix-wc-wiki-ngx-lt>

Let’s hit refresh and open the browser console:

Custom Events to communicate data between Web Components and Container app

So what if we need to send data from one web component to another, for that we’re going to use Custom Events, this communication interface provide us with a clean a cross platform of communication between the web component from different technologies.

Custom Event Dispatcher

In the src/app/app.component.html for the project phoenix-wc-wiki-ngx, let’s create a button with a function sendCustomEvent on click.

<button (click)="sendCustomEvent()">Custom Event</button>

In the src/app/app.component.ts add the function sendCustomEvent with the dispatcher of the custom event.
The name of the custom event {project-name}-ce-{action}

Now that we have the dispatcher, we’re going to add the listener to the web component phoenix-wc-wiki-ngx-lt.

Custom Event Listener

In the src/app/app.component.ts:

  • Create a custom event function in charge of handle the data and call from the custom event. (to handle de data use event.detail)
customEventListenerFunction(event) {console.log('testfunc - ' , event.detail);}
  • Add the listener ot the ngOnInit function to the custom event function
window.addEventListener('phoenix-wc-wiki-ngx-ce-data-sent-test', this.customEventListenerFunction, true);
  • Implement the function ngOnDestroy
implements OnInit, OnChanges, OnDestroy {
  • Add the remove listener to the ngOnDestroy
ngOnDestroy(): void {
window.removeEventListener('changeNameToCustomEvent', this.customEventListenerFunction, true);
}

After we generate the builds and hit refresh to http://localhost:9080/, we can see in the console if we hit the button in the first web component how the phoenix-wc-wiki-ngx-lt-bundle.js executes the function added as a listener.

Lazy Loading Web Components

Let’s add @angular-extensions to the project.

npm i --save @angular-extensions/elements

Append LazyElementsModule to the imports: [] of your AppModule

Add new schemas: [] property with CUSTOM_ELEMENTS_SCHEMA value to @NgModule decorator of your AppModule

After this we can use the *axLazyElement directive to lazy loading the web components.

We have to add variable with the url of the location of url web component.

elementFUrl = 'assets/elements/phoenix-wc-wiki-ngx';or

elementFUrl = 'https://cdn.ourwebhosting.com/1.2.3/elements/phoenix-wc-wiki-ngx';

In the template .html we add the *axLazyElement directive.

<phoenix-wc-wiki-ngx *axLazyElement="elementFUrl"></phoenix-wc-wiki-ngx>

ZoneStrategy

Sometimes the parent application is a Angular app, in order to avoid ngzone conflicts we’re going to use ElementZoneStrategyFactory when we instance the web component.

Just change the ngDoBootstrap in the app.module.ts:

ngDoBootstrap() {const strategyFactory = new ElementZoneStrategyFactory(AppComponent,this.injector);const eventsElement = createCustomElement(AppComponent, {injector: this.injector,strategyFactory});customElements.define('phoenix-wc-wiki-ngx', eventsElement);}

Github links to the repositories:

phoenix-wc-wiki-ngx

phoenix-wc-wiki-ngx-lt

Donations

BTC — bc1qx2alfy4ks8p6gg5y4eantcuwxaefg4wfk42krm

ETH — 0xf21134B4b09F3C1ebF0C8eb386C2EA8D517783fc or hetdev.eth

BCH — qqcxu636r93dne2unp7gdvzdpkwtnx6vlyp3klw48y

LTC — LPQeUXYJ1pThNSLXPJYYHobKEh92sWQyUT

ZEC — t1fkrzNFqwSb2PHtQsKU6i2SVnxmsQMbXKr

--

--