Micro Front Ends — Doing It Angular Style — Part 2

Maor Frankel
Sep 13, 2018 · 4 min read

In the previous part I talked about the motivations for moving towards a MFE solution and some of the criteria for a solution to be relevant. In this part Ill get into how we implemented it at Outbrain.

As I mentioned in the previous part, one of the criteria was for a solution that can integrate with our current technological echo system and require little or no changes to the applications we currently maintain.

Enter Angular Lazy Loading Feature Modules

Angular has a built in concept of modules, which are basically declaration objects that specify all the components, directives, services and other modules that are encapsulated in a module.

@NgModule({
imports: [CommonModule],
declarations: [ WelcomeComponent],
bootstrap: [],
entryComponents: []
})
export class AppB_Module {}

By specifying the module file as a Webpack entry point, this provided us with the ability to bundle up the entire Angular module, including css, and html as a single standalone js file.

entry: {
'appB_module': './app/appB.prod.module.ts'
}

Using Angular lazy loading mechanism, we can dynamically load this js file and bootstrap in into our current application.

const routes: Routes = [
{
path: appB,
loadChildren: '/appB/appB_Module#AppB_Module'
}
]

This is a big step towards our goal of separating our application to a mini application.

Moving from feature modules to mini apps

In order to resolve this we had to create our own Webpack loader which is called share-loader.

Share-loader allows us to specify a list of modules that we would like to share between applications, it will bundle a given module into one of the applications js bundle, and provide a namespace in which other bundles access that modules.

Application A webpack.config:

rules: [
{
test: /\.js?$/,
use: [{
loader: 'share-loader',
options: {
modules: [/@angular/, /@lodash/],
namespace: 'container-app'
}
}]
}

Application B webpack.json

const {Externals} = require('share-loader');externals: [
Externals({
namespace: 'container-app',
modules: [/@angular/, /@lodash/]
})
],
output: {
library: 'appB',
libraryTarget: 'umd'
},

In this example we are telling Webpack to bundle angular and lodash into application A and expose it under the ‘container-app’ namespace.

In application B, we are defining that angular and lodash will not be bundled but rather be pointed to by the namespace ‘container-app’.

This way, we can share some modules across applications, but maintain others that we wish not to share.

So far we have tackled several of the key’s we specified in the previous post, We now have two application that can be run independently or loaded remotely at runtime while wrapped in a js namespace and have css and html encapsulation, They can also share modules between then and encapsulate modules that shouldn’t be shared, now lets look into some of the other key’s we mentioned.

DOM encapsulation

@Component({
selector: 'ob-externals-wrapper',
template: require('./externals-wrapper.component.pug')(),
styleUrls: ['./externals-wrapper.component.less'],
encapsulation: ViewEncapsulation.Native
})

This wrapper component also serves as a communication layer between each mini app and the other apps. all communication is done via an event bus instance that is hosted by each wrapper instance, by using an event system we have a decoupled way to communicate data in and out, which we can easily clear when a mini application is cleared from the main application.

If we take a look at the situation we have so far, we can see that we have a solution that is very much inline with the web component concept, each mini application is wrapped by a standalone component, that encapsulates all js html and css, and all communication is done by an event system.

Testing

Deployment and serving

Example:

A demo is available in the repo itself, enjoy..

Closing Notes:

Moving to a Micro Front End approach is a move in the right direction, as applications get bigger, velocity gets smaller.

This article shows a solution using Angular as a framework, a similar solutions can be achieved using other frameworks.

Outbrain Engineering

Outbrain is the world’s leading native advertising…

Outbrain Engineering

Outbrain is the world’s leading native advertising platform, guiding the digital discoveries of consumers around the globe. Genuinely connecting marketers, publishers, and the consumers in-between, Outbrain serves more than 308 billion recommendations, organically personalizing,

Maor Frankel

Written by

Outbrain Engineering

Outbrain is the world’s leading native advertising platform, guiding the digital discoveries of consumers around the globe. Genuinely connecting marketers, publishers, and the consumers in-between, Outbrain serves more than 308 billion recommendations, organically personalizing,