Interested in Solving your Challenges with XenonStack Team

Get Started

Get Started with your requirements and primary focus, that will help us to make your solution

Proceed Next

Enterprise Digital Platform

Micro Frontend Architecture and Best Practices

Navdeep Singh Gill | 11 December 2024

Micro Frontend Architecture and Best Practices
21:03
Micro Frontend Architecture and Best Practices

Overview of Micro Frontend Architecture

Adopting micro frontend architecture enables teams to build scalable, maintainable, and agile web applications by breaking down complex UIs into independent components. This approach promotes componentization, technology independence, and seamless integration across teams. Using frameworks like micro frontend angular, teams can implement best practices such as API contracts, versioning strategies, and deployment independence. Key strategies like continuous integration (CI/CD), dynamic loading, and monitoring and logging enhance performance and collaboration. By focusing on isolating dependencies and fostering cross-team collaboration, organizations can ensure a flexible and high-performing user experience.

Defining Micro Frontend and Its Concept

Micro frontend is a micro-service testing approach to front-end web development that leverages micro front-end architecture. The current trend is to build a powerful and feature-rich single-page application (SPA) that resides on top of a microservice architecture. Over time, its architecture becomes a part of the application; often, it is developed by a separate team, grows, and gets more difficult to maintain. This type of application is called a frontend monolith. To solve this problem, the concept of micro frontend came into the picture.

The right choice unless we examine the complexity of our frontend ecosystem. Source: Integrate dot js Frameworks to Micro Frontend

A team is cross-functional and develops end-to-end features, from the user interface to the database. It is a more flexible and less bulky approach. This type of micro frontend architecture splits the entire application by business domain across the entire stack. This enables front-end teams the same level of flexibility, testability, and velocity that backend teams get from microservices.

Importance of Architecture

In the modern era, with new web apps, the front end is becoming bigger, and the back end is becoming less important. Most of the code is in its architecture. The monolith approach doesn't work for larger web applications. A monolithic approach to a large front-end application becomes unwieldy. There needs to be a tool to break it up into smaller modules that act independently. The solution to the problem is the micro frontend. Its code is written in pure JavaScript, and any of the JavaScript frameworks used can be migrated from one framework to another.

An approach for developing small services each running in its process for continuous delivery/deployment of large, complex applications. Taken From Article, Microservices Architecture and Design Patterns

Key Benefits of Adopting Micro Frontend

Every day, a new JavaScript technology is invented, and this technology is evolving faster than ever. It can be frustrating, as every JavaScript technology has its own pros and cons. When selecting a particular technology, everyone considers the maximum benefit and minimum risk. Best practices help in using different techniques for different services. Here are some benefits:

  • Support Code and Style Isolation: Each team can choose its own technology stack, ensuring flexibility and reducing dependency.

  • Independent Development and Deployment Independence: Teams can work on different modules independently, enabling faster development and deployment cycles.

  • Continuous Deployment (CI/CD): Facilitates automated deployment, ensuring that updates and new features are delivered quickly and reliably.

  • Simplified Testing: Testing is isolated to smaller modules, so changes don’t require retesting the entire application.

  • Front-end Renovation: Introducing new features or making changes is easier without disrupting the entire system.

  • High Resilience and Better Maintenance: The modular structure allows for improved fault isolation and easier maintenance over time.

A scalable frontend includes small, maintainable, independent, and customisation components that can be served independently. Click to explore about, Top 10 Scalable Frontend Project Principles

Why Microservices are Essential for Frontend

When working on large and distributed web applications, it makes sense to adopt a microservice-based architecture. This approach allows the monolithic team to split into independent teams, improving scalability and reducing code complexity as each team works on a specific feature of the application separately.
The same concept applies to the front-end architecture. It will be part of the same individual team that builds the microservice backend. Each team will own a unique business component and develop it end-to-end, from the user interface to the database layer.

Choosing Micro Frontend Architecture offers several advantages:

  • Technology Agnostic: The architecture gives flexibility to the individual teams to choose the tech stack for their microservice, which improves and makes the development cycle fast with enhanced features.

  • Faster and Isolated Development and Deployment: The development process also improves significantly by adopting its architecture. As with this architecture, we can have smaller independent teams that work on different features, and the development and deployment process becomes faster.

  • Individual Testing and Less Regression Issues: With isolated teams on the front end, the development, testing, and deployment cycles become smoother and help build resilient applications.

  • Maintainability: Monolithic applications are bound to become large and, hence, harder to maintain. It is built on smaller parts to help maintainability through the divide and conquer approach. This ensures easily testable smaller features and the overall time for testing is reduced.

  • Scalability: The modular and decoupled micro frontend architecture allows scaling an application across multiple teams. New front-end elements or changes won’t affect other parts of the front end, allowing teams with different backgrounds and skills to choose the tech stack for their microservice and focus on continuous growth.

Implementing Micro Frontend in Development

The micro frontend provides best practices, strategies, and recipes for building a modern web application with multiple teams using different JavaScript frameworks. The main concept behind its architecture is as follows:
Micro Frontend Architecture

Fig 1: Main Concept Behind Micro Frontend Architecture

 

The main concept behind its architecture is as follows -

Be Technology Independent

Each team should choose and upgrade their tech stack without coordinating with other teams. Custom elements help to hide implementation details while providing a neutral interface to others.

Isolate Team Code

Never share a runtime, even if teams use the same framework. Build an independent, self-contained application. Do not rely on shared state or global variables.

Create Team Prefixes

Use naming conventions where isolation isn’t possible yet. Namespace CSS, Local Storage, Events, and Cookies to avoid collisions and clarify ownership.

Favour Native Browser Features over Custom APIs

Instead of building a global PubSub system, use browser events for communication. If there is a need to build a cross-team API, try to keep it as simple as possible.

Build a Resilient Web design

The features should remain useful even if JavaScript fails to execute. To improve perceived performance, use universal rendering and progressive enhancement.

introduction-icon  Best Practices for Working with Micro Frontend

Different practices to implement its architecture:

  • Single SPA Meta-Framework: The Single SPA meta-framework combines multiple frameworks on the same page without refreshing, such as React, Vue, Angular 1, Angular 2, etc.
  • Multiple Single-Page Applications (SPA) at Different URLs: For shared functionality applications, use NPM or Bower components to manage dependencies across different SPAs.
  • Isolating Micro Apps into Iframes: Use Windows Post Message APIs and libraries to coordinate communication between Iframes. Iframes can share APIs exposed by their parent window.
  • Shared Event Bus for Communication: Different modules can communicate over a shared event bus. Each module can work on its own framework, as long as it handles incoming and outgoing events properly.
  • Component Libraries: Depending on the main app’s stack, develop different components and app sections as libraries and “required” in the main app. Hence, the main app becomes a composition of different components.
D3.js, which stands for Data-Driven Documents, is a front-end visualization library in java-script that creates interactive and dynamic web-based data visualizations. Source: Introduction to D3.js Library

Steps to Successfully Adopt Micro Frontend

This is how you can adopt its architecture and implement Microservices testing with Web components:

Integration in the Browser

Web components provide a way to create fragments of the front end imported into web applications. These fragments can be packaged into microservices together with the back end. Once services are built and completed, both logic and visual representation are packaged together. Using this approach, front-end applications are reduced to routing, making decisions about which set of components are displayed, and orchestrating events between different web components.

Web Components

Web components allow the creation of reusable components that can be imported into web applications. These are like widgets imported into any webpage. They are supported in browsers like Chrome, Opera, and Firefox. If the browser does not support web components natively, compatibility is achieved using JavaScript polyfills. Web components consist of four main elements that can be used separately or together:

  1. Custom Elements

  2. Shadow DOM

  3. HTML Imports

  4. HTML Templates

Custom Elements

Create custom HTML tags and elements with Custom Elements. Each element has its own CSS styles and scripts. Create your own tags, apply CSS styles, and add behaviors through scripts. The only standard required is to use hyphens to avoid conflicts with new HTML elements.
For example, creating a list of check-outs, both with custom elements and custom tags, results in web components and element lifecycle callbacks. These lifecycle callbacks allow defining behaviors specific to the component development. The lifecycle callbacks with custom elements are as follows:

  1. CreatedCallback - Defines behavior that occurs when the component gets registration.

  2. AttachedCallback - Defines behavior that occurs when the component is inserted into the DOM.

  3. DetachedCallback - Defines behavior that occurs when the element is not present in the DOM.

  4. AttributeChangedCallback - Defines behavior that occurs when an attribute is added, changed, or removed.

Best Example of Custom Elements


class CheckoutBasket extends HTMLElement {

constructer (){...} is created

connectedCallback (){...}  attached to DOM

attributeChangedCallback (attr , oldVal , newVal)  someone changed an attribute

disconnecteCallback () {...}  removed from DOM, cleanup events that have been registered
}

Custom elements by default are stencil, svelte, SkateJS, AngularElements, hyperHTML Elements, etc.

Shadow DOM

Shadow DOM is the API that combines HTML, CSS, and JavaScript inside a Web Component, separated from the main document's DOM when these are inside a component. This separation is similar to the one used when building API services, where the consumer of the API service does not know about its internals; the only thing that matters to a consumer is the API requests.
Such a service does not have access to the outside world except to request APIs of other services. Similar features exist in web components. Their internal behavior is not accessed outside, except when allowed by design, nor does it affect the DOM document they reside in. The main method of communication between web components is by firing events.

HTML Imports

HTML imports are the packaging mechanism for web components. They tell the DOM the location of a web component. In the context of microservices, HTML imports refer to the remote location of a service that contains the component to be used. HTML imports are a method to reuse and include HTML documents via other HTML documents.
Predefined components are HTML imports, where each of them includes its own styles and scripts and decides at the top level how the HTML import presents itself in the DOM. The imported document handles the rest of the functionality.

  • Shell (Top-Level Wrapper): A Shell is a top-level wrapper that consists of a container for the component and a component picker. It should include controllers or views that allow the user to manipulate components.

  • Container (Root Place for Nested Applications): The container is the actual root place where the HTML code of nested applications should be injected. For all nested apps, it should have a single entry point.

  • Component Picker (Managing Active Applications): The Component Picker allows the management of nested applications that are active at the moment.

HTML Templates

The HTML template element holds client-side content that is not rendered when a page is loaded. Let's understand the implementation of its architecture using the React JS app example. This approach is useful when web applications are developed independently, allowing changes to elements without blocking or breaking other components.
That’s why in this example, the new React app needs to be built, run, and deployed separately, treating others that need to communicate with it as services. For instance, the example below creates a header for a web page using React.js—a popular framework in modern web development. Let's use create-react-app for fast bootstrap -


npm install -g create-react-app

create-react-app head

cd head/

npm start

Now let’s add server-side rendering real quick. Later it will help when joining apps for SEO and performance reasons. It is easier to attach this at the beginning. micro fronted Then, create a file called server.js at the root of the project that will start an express server and server-side render react-


const path = require('path');

const fs = require('fs');

const express = require('express');

const React = require('react');

const App = require('./transpiled/App.js').default;

const { renderToString } = require('react-dom/server');

const server = express();

server.get('/', (req, res) => {

const htmlPath = path.resolve(__dirname, 'build', 'index.html');

 fs.readFile(htmlPath, 'utf8', (err, html) => {


const rootElem = '

const renderedApp = renderToString(React.createElement(App, null));  res.send(html.replace( rootElem, rootElem + renderedApp) );  server.use(express.static(‘build’)); const port = process.env.PORT || 8080; server.listen(port, () => {  console.log(`App listening on port ${port}`);  }); This script takes the root of the react element (App), renders it to a string, and pushes it into the HTML before serving it to the user. React will later mount on top of that already rendered component. But, that runs on NodeJS, and Node JS doesn't understand JSX or other newer syntaxes like import, so Babel used to transpile it before running the server-


npm install --dev babel-cli babel-preset-es2015

Add two tasks to the scripts section in package.json to run that-


"transpile": "NODE_ENV=production babel src --out-dir transpiled --presets es2015,react-app",

"start:prod": "NODE_ENV=production node server.js"

That's it. Now run the header with-


npm run build

npm run transpile

npm run start:prod

Scaling Frontend with Micro Frontend Architecture

Now that we know why micro frontend architecture is the future of frontends and how it helps to scale our applications, we can understand how to implement it. To have control over the team's code and how the work between the teams should be allocated for a well-functioning architecture, we must first understand the best way to split the application's codebase.
The codebase can be split between the teams according to the vertical slices of business functionality instead of technical capabilities. In a vertical split, we prioritize business domains and assign each domain to different teams. Since responsibility for the entire interface would be with a single team, this gradually helps the teams gain more expertise in that specific business domain. There are many ways to implement micro frontend architecture, and the method you choose depends on the application's needs.

Server-side Composition

With server-side composition, a service typically sits between the browser and the application servers. One of the key benefits of using server-side composition is that the page that reaches the customer's browser is already fully assembled. The micro frontends are cached at CDN (Content Delivery Network) and then served to the client or user at build time.
The server composes it into a view that is later served at build time, retrieves it, and organizes and assembles the final page. This helps increase page load speed, which is significantly higher than that of pure client-side integration techniques. Additionally, it increases the robustness of the application.

An open-source platform that automates container operations, Minikube is best for testing kubernetes. Click to explore, Java Microservices Application on Kubernetes.

Build-time Integration

The build time integration could be done using web components or any component-driven frameworks. One of the approaches is to publish it as a package and then use a container application to incorporate them as library dependencies. This integrates the components at build time and helps keep a fully decoupled build pipeline for each of the frontends. This helps in achieving effective collaboration and code reuse. If we look at package.json, the container application uses the micro frontends as a package.

Runtime via JavaScript

The runtime integration approach bundles and configures the micro frontends at runtime. A package.json is not used to bundle the individual components. One way to implement runtime integration is via JavaScript. Runtime integration via JavaScript is the most flexible approach that teams use for micro frontend implementation.
In this approach, each micro frontend is incorporated into the page using a <script> tag. The script tag doesn't render anything immediately upon load, but it attaches global functions as entry points. The container application then determines which should be mounted and calls the relevant function to tell it when and where to render itself.

manage-the-full-lifecycle-of-ml-in-production
Want to scale frontend development to make your teams work together? Contact our Microservices Experts

Runtime via Web Components

Another alternative for runtime integration is using web components. In runtime integration via web components, each micro frontend defines an HTML element for the container to represent an instance instead of defining a global function called by the container. Web components are isolated components that can be (re)used in HTML pages and web applications. These are also known as custom elements.

Runtime Via Frames

One of the simplest ways to compose the application in the browser and build pages from autonomous sub-pages is through runtime integration via iframes. Developers can achieve better isolation in global variables and style with iframes. Iframes are HTML documents that could be embedded inside another HTML document, making it easy to build pages from independent sub-pages. Spotify has shared that it uses iframes to stitch together different parts of the view.

Final Insights on Micro Frontend Architecture

 

Make sure the core and the integration are as simple as possible in micro frontend architecture. One of the critical challenges is to standardize the UI/UX principles. A universal solution is to use a style guide, such as Material Design, Bootstrap, or others. Communication with the team is key to ensuring everything is running smoothly. Establishing standards and rules can help minimize conflicts between different teams working on the product.
All these micro frontend architecture best practices help to solve one primary issue: scalability. As an application grows significantly, it introduces numerous issues and conflicts. By splitting the codebase across teams and applying the right logistics, it is possible to deliver high-quality, technology-trending, and fast solutions to the world.

Next Steps for Implementing Micro Frontend

Talk to our experts about implementing Micro Frontend architecture. Learn how industries and teams can leverage modular development, achieve deployment independence, and enhance cross-team collaboration. Utilize technology independence and continuous integration (CI/CD) to optimize front-end development, improve scalability, and boost overall application performance.

More Ways to Explore Us

Microservice Architecture vs. Monolithic Architecture

arrow-checkmark

Integration of dot js Frameworks to Micro Frontend

arrow-checkmark

Java Microservices for Scalable Applications

arrow-checkmark

 

Table of Contents

navdeep-singh-gill

Navdeep Singh Gill

Global CEO and Founder of XenonStack

Navdeep Singh Gill is serving as Chief Executive Officer and Product Architect at XenonStack. He holds expertise in building SaaS Platform for Decentralised Big Data management and Governance, AI Marketplace for Operationalising and Scaling. His incredible experience in AI Technologies and Big Data Engineering thrills him to write about different use cases and its approach to solutions.

Get the latest articles in your inbox

Subscribe Now