Microfront-end: Reinventing THE UI in a world of microservices

We were amazed at the way the software industry developed! Software used to be simple programs. The earliest software, such as the Apollo mission landing module and the Manchester Baby, was a rudimentary stored procedure. The main purpose of the software is for research and mathematics.

The invention of the personal computer and the rise of the Internet changed the world of software. Word processors, spreadsheets and games are on the rise. Websites also emerged, with web pages read as static documents. By the mid-1990s, with the introduction of Netscape’s client-side scripting language and JAvascript and Marcromedia’s introduction of Flash, browsers had become more powerful and websites had become more exciting and interactive. Still, the development that has been applied is simple. Engineers didn’t pay enough attention to building them.

The emergence of disruptive technologies such as cloud computing and big data has paved the way for more sophisticated Web and native mobile applications. From e-commerce and video streaming applications to social media and photo editing, software applications are increasingly taking on the most complex tasks of data processing and storage. Traditional monolithic architectures face significant challenges in terms of scalability, team collaboration, and integration/deployment, and can lead to a large and chaotic code base.

To solve this problem, various service-oriented architectures are emerging. One of the most promising is the microservices architecture – the dismantling of a single working module that can be developed, deployed, and tested independently. Its extensibility and ability to be released by multiple teams at the same time proves it to be a great solution to most architectural problems. Some client-facing front-end architectures are emerging, such as MVC, MVVM, Web Components, and so on, but they don’t fully reap the benefits of microservices.

Micro front end: Concept

The microfront end first appeared at ThoughtWorks Technology Radar, where they tried, validated and finally adopted the microfront end. It is a microservice approach to Web development that combines independently running front-end applications into a whole!

With the idea of microservices, the microfront end breaks the front-end monolithic architecture and creates a complete microarchitecture design pattern for Web applications. It consists entirely of loosely coupled vertical modules of business functionality, rather than horizontal modules. These vertical modules are called “microapplications”. This concept is not new. In Scaling with Microservices and Vertical Decomposition, it was proposed for the first time that each Vertical module is responsible for a separate business, and the concepts of presentation layer, persistence layer and separate database were also proposed. From a development perspective, each vertical is implemented by a team, and no code is shared between different systems.

Advantages of a micro front end

The micro front end has many advantages over the monomer architecture.

  • Easy to upgrade

    The microfront end constructs a strictly bounded context in an application. Standalone applications are updated in a more isolated and growing way, and you don’t have to worry about breaking parts of the application.

  • scalability

    Horizontal scaling is extremely easy with a micro front end. Each microfront is guaranteed to be stateless for scaling.

  • Easy to deploy

    Each microfront has its own CI/CD pipeline that can be built, tested, and deployed into a production environment. Therefore, it doesn’t matter if other teams are working on a feature and driving bug fixes, or if switching or refactoring is in progress. As long as one team is responsible for a micro front end, changes on the micro front end should be risk-free.

  • Teamwork and ownership

    The Scrum guide says that “the best development teams are small enough to stay agile and large enough to get important work done in sprints”. The microfront is ideal for applications where multiple cross-functional teams (microfronts) can fully own the stack, from user experience to database design. If it’s an e-commerce site, the product team and the payments team can work on the application at the same time without stepping on each other.

Microfront-end integration approach

There are many ways to implement a micro front end, but it is recommended to use runtime integration, not build-time integration, in any case. Because the former must recompile and publish on each microfront in order to publish any changes to the microfront.

Next, we’ll learn how to highlight the micro front end by building a simple pet e-commerce hotel. The site has micro-applications such as page or search, shopping cart, checkout, products and Contact us. We will only demonstrate the micro front end of the site. Assume that each microapplication has a microservice that serves it. You can view project demos and code libraries. Each integration approach has a branch in the REPO code that you can check out to see.

Single page front-end

The simplest (but not the most elegant) way to implement a microfront is to treat each microfront as a page.

micro-frontend.html

! DOCTYPE html><html lang="zxx">

<head>

	<title>The MicroFrontend - eCommerce Template</title>

</head>

<body>

  <header class="header-section header-normal">

    <! -- Header is repeated in each frontend which is difficult to maintain -->. . </header<main>

  </main>

  <footer

    <!-- Footer is repeated in each frontend which means we have to multiple changes across all frontends-->

  </footer>

  <script>

    <! -- Cross Cutting features like notification, authentication are all replicated in all frontends-->

  </script>

</body>

Copy the code

This is one of the purest ways to do a microfront end, because there are no containers or concatenation elements to bind the front end to the application. Each microfront is a separate application in which each dependency is encapsulated and there is no coupling. The downside of this approach is that pages have a lot of duplication (such as headers and footers), which adds redundancy and maintenance.

JavaScript rendering component (or Web component, custom element) –

As we saw above, the single-page micro-front-end architecture has its drawbacks. To overcome this, we should choose an architecture that has a container element to build the application’s context and crosscutting concerns (such as authentication), and splices all the microfronts together to create a cohesive application.

MicroFrontend.js


// A virtual class from which all micro-frontends would extend

class MicroFrontend {

  

  beforeMount() {

    // do things before the micro front-end mounts

  }

  onChange() {

    // do things when the attributes of a micro front-end changes

  }

  render() {

    // html of the micro frontend

    return '<div></div>';

  }

  onDismount() {

    // do things after the micro front-end dismounts }}Copy the code

Cart.js


class Cart extends MicroFrontend {

  beforeMount() {

    // get previously saved cart from backend

  }

  render() {

    return ` <! -- Page --> <div class="page-area cart-page spad"> <div class="container"> <div class="cart-table"> <table> <thead> . `

  }

  addItemToCart(){... } deleteItemFromCart () { ... }applyCouponToCart(){... }onDismount() {

    // save Cart for the user to get back to afterwards}}Copy the code

Product.js


class Product extends MicroFrontend {

  static get productDetails() {

    return {

      '1': {

        name: 'Cat Table'.img: 'img/product/cat-table.jpg'

      },

      '2': {

        name: 'Dog House Sofa'.img: 'img/product/doghousesofa.jpg'}}},getProductDetails() {

    var urlParams = new URLSearchParams(window.location.search);

    const productId = urlParams.get('productId');

    return this.constructor.productDetails[productId];

  }

  render() {

    const product = this.getProductDetails();

    return ` <! -- Page --> <div class="page-area product-page spad"> <div class="container"> <div class="row"> <div class="col-lg-6"> <figure> <img class="product-big-img" src="${product.img}" alt="">`

  }

  selectProductColor(color) {}

  selectProductSize(size) {}

 

  addToCart() {

    // delegate call to MicroFrontend Cart.addToCart function}}Copy the code

index.html


<! DOCTYPEhtml>

<html lang="zxx">

<head>

	<title>PetStore - because Pets love pampering</title>

	<meta charset="UTF-8 stylesheet" href="css/style.css"/>

</head>

<body>

	<! -- Header section -->

	<header class="header-section">.</header>

	<! -- Header section end -->

	<main id='microfrontend'>

    <! -- This is where the Micro-frontend gets rendered by utility renderMicroFrontend.js-->

	</main>

                                <! -- Header section -->

	<footer class="header-section">.</footer>

	<! -- Footer section end -->

  	<script src="frontends/MicroFrontend.js"></script>

	<script src="frontends/Home.js"></script>

	<script src="frontends/Cart.js"></script>

	<script src="frontends/Checkout.js"></script>

	<script src="frontends/Product.js"></script>

	<script src="frontends/Contact.js"></script>

	<script src="routes.js"></script>

	<script src="renderMicroFrontend.js"></script>

Copy the code

renderMicroFrontend.js


function renderMicroFrontend(pathname) {

  const microFrontend = routes[pathname || window.location.hash];

  const root = document.getElementById('microfrontend');

  root.innerHTML = microFrontend ? new microFrontend().render(): new Home().render();

  $(window).scrollTop(0);

}

$(window).bind( 'hashchange'.function(e) { renderFrontend(window.location.hash); });

renderFrontend(window.location.hash);

utility routes.js (A map of the hash route to the Microfrontend class)

const routes = {

  The '#': Home,

  ' ': Home,

  '#home': Home,

  '#cart': Cart,

  '#checkout': Checkout,

  '#product': Product,

  '#contact': Contact,

};

Copy the code

This approach is very succinct and encapsulates a single class for the microfront end. All other microfronts extend from this. Notice how all of the functionality associated with microapplications is encapsulated in the corresponding microfront end. This ensures that concurrent work on the micro front end does not mess up the other micro front ends.

When it comes to Web components and custom elements, everything will work in a similar paradigm.

React

Because client-side JavaScript frameworks are so popular, it’s impossible to rule React out of any front-end discussion. React is a component-based JS library, and much of the discussion above applies to React as well. I’ll discuss some of the technical details and challenges surrounding the React Micro front end.

style

Because there should be minimal code sharing between any micro-front ends, styling the React component can be challenging given the global and cascading nature of CSS. We should make sure that styles are specific to a particular microfront and don’t spill over to other microfronts. Radium and CSS Modules can be used with React.

Redux

In today’s front-end world, using React with Redux is the norm. The convention is to use Redux as a single global store for the entire application for cross-application communication. The microfront end should be independent and have no dependencies. Therefore, each microfront-end should have its own Redux storage, moving toward a multi-REDUx storage architecture.

Other noteworthy integration approaches

  • Server-side rendering

    A microfront-end template can be assembled using a server and then rendered to a browser. SSI techniques can also be used.

  • iframes

    Each microfront can be an IFrame. They also provide a good degree of isolation in terms of style, and global variables do not interfere with each other.

summary

With microservices, the microfront end promises many benefits for building complex applications, as well as for development, deployment, and maintenance.

There is a famous saying: “There is no one-size-fits-all approach that anyone can offer you. The same hot water that softens a carrot hardens an An egg.” The micro front section is good, but it doesn’t solve all architectural problems, and it has its drawbacks. As more repositories, tools, build/deploy, servers need to be maintained. Microfrontend can also add complexity to an application. It is difficult to establish communication across applications, and the duplication of dependencies magnifies the size of the program.

Whether or not to adopt a micro-front-end architecture depends on many factors. Such as the size of the organization and the complexity of the application. Whether it is a new project or a legacy large code base, it is recommended that this technique be applied gradually over time and checked to see if it works.