Building a MicroFrontend setup using Angular 12: Part 3 —Specific problems and solutions

Jonathan Cardoz
6 min readJan 23, 2022

--

Photo by Olav Ahrens Røtne on Unsplash

Disclaimer: This is my first set of articles on Medium and since I haven’t blogged or written anything (other than social media posts or restaurant reviews) for a couple of years, please bear with me. Comments are welcome.

I hope this set of articles helps you in understanding Micro Frontends (referred to as MFEs from now on), to setup your project and not make the same set of mistakes that my team and I did.

The other articles in the series are linked below

This article lists out the specific problems me and my team faced and solutions to them. As always — this solution was the one which helped us to solve the problem at hand, but might not be the best solution. If you have faced a similar problem, but used a different solution, put in your suggestions so we can learn together.

Using a common component library

TLDR: For repeated functionality or widgets, either use a pre-built component library — or build one from scratch. Use version control to handle new code— so that this doesn’t mess with your MFE development

The main problem solved was consistency. It prevented replication of code. Keep the following points in mind when building a common component library:

  • Keep your components independent of business logic.
  • Always make the components configurable. Use @input properties to allow authors to modify the component for their specific use case. It pays to know upfront about the different scenarios where your component will be used. This will allow you to draft a set of features instead of having to revisit the component at a later stage.
  • Emit events to ensure parent components are aware of any change in the component.
  • Do not rebuild the wheel. Look for existing components before setting out to build complicated widgets. This will save you a lot of time and frustration.

In addition to abstracting out common pieces of code, the library also allowed us to work in parallel without having to worry about our changes affecting the application. This was due to versioning and using the package version to handle any new change. Once the component had overall unit test coverage over 80%, we were confident that it would work in almost all cases. We used lerna as a tool to handle version upgrades and generate a changelog.

To install a pre-existing component library, is quite simple. I have added ng-bootstrap — a collection of widgets to the shell application to illustrate the point.

The steps are as follows:

Step 1: Add the package to your package.json. For ng-bootstrap, you can use the following angular CLI command

ng add @ng-bootstrap/ng-bootstrap

Step 2: Add the appropriate CSS (this may or may not be needed — based on the package you are including. As ng-bootstrap relies on Bootstrap CSS for styling, we need to perform this step).

Note: Add the SCSS or CSS file — based on which you are using in your project. I am using CSS so I have added the CSS output file.

// file: SampleAngularWorkspace/projects/shell/src/styles.css
@import "~bootstrap/dist/css/bootstrap.min.css";

Step 3: Include the module into your application module / consuming module. Bonus tip: Use the specific module (or named import) — this will save on your overall project size. Here, I am importing the NgbButtonsModule module as I only want to use the button component.

import { NgbButtonsModule } from '@ng-bootstrap/ng-bootstrap';......@NgModule({declarations: [...],imports: [...NgbButtonsModule],providers: [],bootstrap: [AppComponent]})export class AppModule { }

Step 4: Use the component within your page

<!-- app.component.html --><button class="btn btn-primary" ngbButton (click)="callButtonClick()">Test</button>

The feature/part-3 branch of the repository has the working code with a button component included.

Handling static assets from remotes in the shell MFE

TLDR: Use the angular.json to transfer your static assets from `remote` to `shell` MFE to prevent broken links

Your images, icons and other resources such as language json files from the remote MFE will show up as broken links in the shell MFE. This is because the relative paths which work when used when running the project in standalone mode, will not resolve in the shell MFE. In order to get around this issue, we use some fancy ‘configuration’ foot-work — with a little help from the angular.json file.

Step 1: Name your asset files based on your remote name. So for example, in our case, consider saving an image or icon, we have app1 as the remote MFE — so we name the images folder as assets/app1-images or something similar say assets/app1-icons

name the folder app1-images or app1-icons as per the assets within it

Step 2: Within the angular.json file, navigate to the shell configuration object and add the following to the assets property

{"glob": "**/*","input": "projects/app1/src/assets","output": "assets"}

Breaking this down, glob property will look in the input folder mentioned, and copy all the files to the shell output folder. We are using the * or wildcard character to identify all folders and all files within those folders.

Now, in the shell folder we should see, our new app1-images folder, if we run a build. Similarly, when we load the remote application from shell, we should see the image correctly.

sample image from app-1 is visible in the shell MFE

The feature/part-3 branch of the repository has the working code. You can refer to the angular.json configuration for further reference. In the same way, you can also import and handle CSS from common components / libraries

CODEOWNERS

TLDR: Use CODEOWNERS files to provide folder based reviewer information for specific projects within your monorepo

Monorepos have their fair share of advantages, but they also are difficult to handle, with many teams working on the same repository.

For a new developer, it might be difficult to determine who to raise a pull request to? CODEOWNERS files aim to solve this problem. They can be placed within a project or a specific folder, and whenever that folder is referenced in a pull request, the person(s) mentioned will be added automatically as code reviewer (s).

Step 1: Create a file and simply name it CODEOWNERS Do not provide any extension. Place this file in the specific project src folder

Step 2: Add the github userId of the code reviewer you wish to include. You can check their Github profile to find their userId.

You can refer to the CODEOWNERS configuration file for further reference.

Using a core frontend to house the other frontends

TLDR: Keep cross cutting features like authentication in your `shell` MFE

The shell MFE was used for authentication, authorization and navigation concerns. Common concerns which will be vertical agnostic or cutting across all the different projects can be placed here. You most likely will have the same authentication throughout your different MFEs — so it makes sense to put the logic here. Similarly, you will have specific routing mechanisms in place.

Using a library to house common services and functions

TLDR: Use a library to keep common services or functions

Like a common component library, you can also use a library within your Angular workspace to host common services and utilities that will be used across the different MFEs in your project. For example, you need to display the user information from the authentication token within a MFE. The way in which you display this information might change, but the service will be the same in each case. Say for example, you need to format dates in a common manner across MFEs. This service or utility can be moved to a library and then referenced as a shared package. Part-2 of this series talks about this in more detail.

In fourth and final part of the series, we will look at the different learnings and take-aways from the exercise of building an MFE with Angular.

Leave a comment if you encountered any specific problem when running this setup. Thank you for reading, and see you in the next one.

--

--