[Micro frontends] Getting Started
Tags: webdev, tutorial, angular, programming
Published: 2023-02-10 08:09:38

At the beginning of this week, I took a course on micro frontends architecture topic. It's such a buzzword when it comes to frontend development, but I've never attempted anything in practice until this week.

### Table of contents
1. [Introduction](#introduction)
2. [Application architecture](#app-architecture)
3. [Prerequisites](#prerequisites)
4. [Step-by-step tutorial](#tutorial)
5. [Conclusion](#conclusion)
6. [Additional resources](#resources)

### Introduction <a name="introduction"></a>

When it comes to microservices, the backend services have this architecture in place for several years already. So why not taking advantage of all the benefits and start developing micro applications / micro components that can be owned, developed, managed and maintained by different teams. Of course, that's only one of the advantages (vertical teams that will handle a feature end-to-end), but we can also talk about the ability to scale the product by working on different features / modules in parallel,  speed of delivery, support for innovation and new technologies, more reliable testing and maximum decoupling.

Let's see how it goes in practice!

### Application architecture <a name="app-architecture"></a>

I've decided to start from the well-known Angular Tour of Heroes tutorial and split the codebase into micro apps. There are a few approaches when it comes to splitting monolithic applications into micro frontends, I chose to do it by feature. The application provides two major features:

- dashboard:  top heroes + search heroes capability
- heroes: list of heroes + hero management capabilities (view here, add hero, delete hero)


![Tour of heroes dashboard page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3i5d5dihb89mq2ua1n1k.png)

![Tour of heroes hero page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7d4q24ev6mcjsnqn32sl.png)

Considering the split by feature, I've decided on the following architecture of my application:


![Tour of heroes architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0gmi9ddn6ba8o9doepf5.png)

where:
- *shell application* is the app that will host all the remote micro applications (dashboard and heroes) and will handle everything related to the navigation (navigation component and routing logic)
- *dashboard micro application* is one of the remote applications, targeting the dashboard feature
- *heroes micro application* is the second remote application, targeting the heroes feature

### Prerequisites for Angular micro frontends: <a name="prerequisites"></a>
- NodeJs 10.13.0+
- Webpack 5
- Angular 12+
- NX

### Step-by-step tutorial <a name="tutorial"></a>

🔸 download the [Angular Tour of Heroes](https://angular.io/tutorial/tour-of-heroes/toh-pt0) application 
🔸 open terminal to the root directory and run
```bash
npm i && npm install -g nx
```
🔸 transform the Angular cli workspace to an integrated NX monorepository (all the micro frontends will be part of the NX monorepo for simplicity)
```bash
ng add @nrwl/angular@<version_number>
```
🔸 get rid of all the unused files, configs, packages and components to keep it simple and focus on the micro apps (remove the message component and e2e files)
🔸 run the application locally to check that all the changes made so far didn't affect the app 
```bash
npx nx build tour-of-heroes
```
So far, you should be able to navigate to `http://localhost:4200` and check the application in the browser.

Let's keep having fun:

🔸 generate NX Angular application for dashboard-microapp and hero-microapp using nx cli
```bash
npx nx generate @nrwl/angular:app dashboard-microapp
```
```bash
npx nx generate @nrwl/angular:app heroes-microapp
```
🔸 add angular module federation plugin to all apps (shell, dashboard, hero)
```bash
npx nx g @angular-architects/module-federation:init 
--project tour-of-heroes --port 4200 --type host
```
```bash
npx nx g @angular-architects/module-federation:init 
--project dashboard-microapp --port 4201 --type remote
```
```bash
npx nx g @angular-architects/module-federation:init 
--project heroes-microapp --port 4202 --type remote
```
> This command will do a couple of things: add webpack.config.js, webpack.prod.config.js, bootstrap.js files and additional configurations (more details [here](https://nx.dev/recipes/module-federation/dynamic-module-federation-with-angular#what-was-generated))

The `apps` folder should look like this:

![Application folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ixcy5gd1fj9ioenx0vh.png)

🔸 let's consider the dashboard-microapp (same will apply to hero-microapp). At this point, in `src` folder, you have an Angular app configuration - with app.module, app.component.ts, app.component.html and app.component.css. We're going to create a new component, module and routing for the Dashboard feature
```bash
ng generate module dashboard --project=dashboard-microapp
```
🔸 move the logic from the initial application (dashboard and hero-search components) to the dashboard application (you can copy paste the components and update the imports in case the IDE doesn't handle it)
🔸 configure the `dashboard.module.ts` as follow (by importing modules, declaring routes and components):
```js
export const remoteRoutes: Route[] = [ 
  { path: '', component: DashboardComponent }, 
];

@NgModule({ 
  imports: [ 
    CommonModule, 
    HttpClientModule, 
    FormsModule, 
    RouterModule.forChild(remoteRoutes), 
  ], 
  declarations: [DashboardComponent, HeroSearchComponent], 
}) 
export class DashboardModule {}
```
🔸 expose DashboardModule in `webpack.config.js`:
```js
const { 
  withModuleFederationPlugin, 
} = require('@angular-architects/module-federation/webpack');

module.exports = withModuleFederationPlugin({ 
  name: 'dashboard-microapp', 
  filename: 'remoteEntry.js', 
  exposes: { 
    './Module': 
      './apps/dashboard-microapp/src/app/dashboard/dashboard.module.ts', 
  }, 
});
```
🔸 now that you got the functionality moved to the micro-app and the module configured for this feature, update the app.module.ts:
```js
@NgModule({ 
  declarations: [AppComponent], 
  imports: [ 
    BrowserModule, 
    HttpClientModule, 
    // optional: setting in-memory-web-api for microapps so we can test them separately 
    HttpClientInMemoryWebApiModule.forRoot(InMemoryDataService, { 
      dataEncapsulation: false, 
    }), 
    RouterModule.forRoot( 
      [ 
        { 
          path: '', 
          loadChildren: () => 
            import('./dashboard/dashboard.module').then( 
              (m) => m.DashboardModule 
            ), 
        }, 
      ], 
      { initialNavigation: 'enabledBlocking' } 
    ), 
  ], 
  providers: [], 
  bootstrap: [AppComponent], 
}) 
export class AppModule {}
```

To test everything related to dashboard-microapp, let's run it in the browser and see what we get:
```bash
npm start dashboard-microapp
```
> navigate to http://localhost:4201 and you should be able to see the dashboard app:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x37fnfl4r5lfstzqsjfu.png)

🔸 repeat the same steps for hero-microapp (generate module, move functionality, update hero.module.ts file and app.module.ts, run it in browser and check that everything works as expected).

So far, we have 2 microapps that are running independently in the browser, how do we integrate them into the shell application so we can create the illusion of a single application for the end user? 

🔸 switch to shell application (tour-of-heroes) and adjust webpack.config.js:
```js
const { 
  shareAll, 
  withModuleFederationPlugin, 
} = require('@angular-architects/module-federation/webpack');

module.exports = withModuleFederationPlugin({ 
  remotes: {}, 
  shared: { 
    ...shareAll({ 
      singleton: true, 
      strictVersion: true, 
      requiredVersion: 'auto', 
    }), 
  }, 
});
```
> keep remotes: {} for dynamic consumption of micro applications

🔸 load the micro apps lazily when it's routed to:
```js
const routes: Routes = [ 
  { 
    path: '', 
    loadChildren: () => 
      loadRemoteModule({ 
        remoteEntry: 'http://localhost:4201/remoteEntry.js', 
        type: 'module', 
        exposedModule: './Module', 
      }).then((m) => m.DashboardModule), 
  }, 
  { 
    path: 'heroes', 
    loadChildren: () => 
      loadRemoteModule({ 
        remoteEntry: 'http://localhost:4202/remoteEntry.js', 
        type: 'module', 
        exposedModule: './Module', 
      }).then((m) => m.HeroesModule), 
  }, 
];
```

🔸 run all the applications 
```bash
npm run run:all
```
and navigate to http://localhost:4200. You should be able to see the Tour of heroes application - same as in the beginning, because nothing changed for the end user. 

Hoooray! That was it! 🥳

### Conclusion <a name="conclusion"></a>

This is my first attempt at micro frontends, I hope it clarifies the initial steps and configuration of the micro frontend architecture and encourages you to consider it for your future projects. I'll keep playing with it and document my stories while learning new stuff, so stay tuned! ^_^


### Additional resources: <a name="resources"></a>
- [Angular Tour of Heroes](https://angular.io/tutorial/tour-of-heroes)
- [Angular Tour of Heroes code](https://angular.io/tutorial/tour-of-heroes/toh-pt0)
- [Migrate Angular workspace to Nx monorepo](https://nx.dev/recipes/adopting-nx/migration-angular#transforming-an-angular-cli-workspace-to-an-integrated-nx-monorepo)
- [Angular Module Federation](https://www.angulararchitects.io/en/aktuelles/the-microfrontend-revolution-module-federation-in-webpack-5/)
- [Advanced Angular Micro Frontends with Dynamic Module Federation](https://nx.dev/recipes/module-federation/dynamic-module-federation-with-angular)
- [Pluralsight Micro Frontends Architecture](https://app.pluralsight.com/library/courses/micro-frontends-architecture/table-of-contents)
- [Github repo](https://github.com/blminami/tour-of-heroes-microfrontends)

Until next time, thank you for reading! 🐾