Front-end Microservices Architecture

Mykhailo Churilov

Lead Software Engineer

Preconditions

Application Scale

To-do App

Average Enterprise

Damn big app

Lead Developer

Middle Developer

Standalone App #1

Standalone splitting

Standalone App #1

Legacy Mono App

Redirect to external

Back-end

REST communication

JWT

Standalone splitting

Standalone splitting

  • TypeScript
  • Component structure
  • Self generated docs
  • UI library

Text

App #2

Requirements

  • Divide Legacy system to multiple apps, to make possible split the Team
  • Have consistent UI across all applications
  • Make single authentication point to all applications, without code duplication

New Team

Shell keeper

App#1 Keeper

App#2 Keeper

App#3 Keeper

Research

Iframe

  • Content Scroll
  • Nesting level
  • Bundle size

Downsides

StackOverflow

Polymer

Web Comonents

Polyfills

Theory

Shell

Header

Container

App #1

App #2

App #3

CSS, HTML

CSS, HTML

CSS, HTML

inners CustomElement depend on the route

/app1/root/route

changes route

Script Loader

Identity Service

defines
custom elements 

UI lib

Header Component

Responsibilities:

  • changes location url

Script Loader

Responsibilities:

Parses elements schema

Creates node for each item

Register custom DOM element for each node

const components = [{
        name: 'vue',
        scriptName: 'vue-bundle.min.js',
        template: '<div id="app"></div>',
        cssPath: null
    }, {
        name: 'angular',
        scriptName: 'ng-bundle.min.js',
        template: '<app-root id="app"></app-root>',
        cssPath: null
    }];
components.forEach((el) => {
  const node = Object.create(HTMLElement.prototype);

  node.attachedCallback = () => {
    const remote = DEFAULT_PATH;

    this.appendChild(
      document.createRange()
      .createContextualFragment(el.template)
    );

    $.getScript(remote + '/' + el.scriptName)
      .done(() => {
        window[el.name] = true;
      });

  };

  document.registerElement(el.name + '-app', {
    prototype: node
  });
});

Container

1. Parses app name in the route

2. Inserts {{app_name}}-app to the DOM

Routing - single point of truth

/app1/products/12

/app2/products/12

/error_page

app1 loaded

app2 loaded

no app loaded

Apps communication

App #1

App #2

App #3

CSS, HTML

CSS, HTML

CSS, HTML

Wrapper

Shared Store

Real Battle

ROUTE: /angular/home

ROUTE: /vue/home

For what?

WTF?

App#1 Keeper

App#2 Keeper

App#3 Keeper

events leaks

CSS inject duplications

styles overriding

Resources Guard

Resource management service

Container Stage

Active app #cur

Store events for #cur
Release events for #last
OnAppActivated()

app #1

app #2

app #3

Resource management service

Micro-apps restrictions

Isolate own styles

Prevent app run on the different app in location

Keep tracking all listeners, so on Exit of app we can easily destroy them

Bootstrap application from JS code

Forget about document and window

Deployment

CDN for app #1

v_1

v_2

v_3

CDN for app #2

v_1

v_2

v_3

CDN for app #3

v_1

v_2

v_3

Shell

Script Loader

Server

{Config}

GET app#1 v_2

app_1_v_2
bundle

Testing

1. Unit Testing of micro-apps

2. E2E

3. Resources Guard

4. Visual testing

Q & A

@kobvel

Front-end Microservices Architecture

By Mikki Churilov

Front-end Microservices Architecture

Slides to public talk about building front-end microservices architecture for large enterprise apps.

  • 951