Implementation of Micro Frontends

Prev article: Theory of Micro Frontends Part - 2

Contents:

  1. Tools for Implementation
  2. Steps to Code
  3. Best Practices


There are many ways to implement MicroFrontends. Any Javascript framework can share and consume MFE components and thus revolutionizing the web world by making it framework independent.

As shown below, Multiple components from multiple apps can be shared and used under one container application.

MFE container
MFE Implementation

Implementation

Popular Frameworks:

Some of these toolsets are a driving force behind the development, release, and reuse of independent components:

  • Bit: It is one of the most popular production-ready solutions that lets you build and manage frontends with the help of independent components.
  • More: Bit - Component driven development
  • Module Federation: A JavaScript architecture that allows you to import code for other applications dynamically at run time.
  • More: Module Federation | webpack
  • Single SPA: Another JavaScript framework that adds a lifecycle to applications. Each app can, then, respond to URL routing and knows how to unmount, mount, and bootstrap from the DOM.
  • More: single-spa | single-spa
  • Piral: This enables you to leverage the Micro Frontend architecture through modular frontend apps that are extended at runtime with the help of decoupled modules known as Pilets.
  • More: Piral - Portal Solutions using Microfrontends

Module Federation gives us a new method of sharing code between front-end applications.

Module Federation is a plugin that is added to Webpack. It adds the flexibility of exposing remote components.

It adds the option to share and integrate components in run-time. Loads the components through remoteEntry.js and wouldn't interfere with the other existing components and linked micro frontends.


Steps to Use

Since Module Federation is a part of webpack and webpack is the primary build tool used for all the existing web apps, Module Federation approach would give us more advantage.

Code Reference:

Following are the step for configuring, sharing and consuming React Components as Micro Frontend components between two different applications.

  1. Configuring Micro-Frontend Service for exposing components out of an Application

  • Add Module Federation plugin to the webpack-config file of the First App(MFE Sharing App)

const webpack = require('webpack');
const { ModuleFederationPlugin } = webpack?.container;
const dependencies = require('./package.json')?.dependencies;

new ModuleFederationPlugin({
    name: 'mfe-app-1',
    filename: 'remoteEntry.js',
    // ? Add the list of components which are to be exported as Microfrontends.
    exposes: {
        "./CounterAppOne": "./src/components/CounterAppOne",
    },
    shared: {
        react: { singleton: true, eager: true, requiredVersion: deps.react },
        "react-dom": {
          singleton: true,
          eager: true,
          requiredVersion: deps["react-dom"],
        },
        ...dependencies // ? Share all the dependencies only if needed.
    },
})        

  • Configure the components which are to be exposed as Micro Frontend Services into the "shared" property of the Plugin. Share the needed dependencies along with the exposed components.
  • remoteEntry.js file will hold the Module Federation configurations.
  • After adding the Module Federation Plugin, you should be able to access your shared component transpiled code at: <APP-URL>/remoteEntry.js
  • Ex: https://localhost:3001/remoteEntry.js

  1. Consuming the exposed Micro-Frontend components into a Host Application

  • Add Module Federation plugin to the webpack-config file of the Second App
  • (MFE Host App)


new ModuleFederationPlugin({
  name: "container",
  remotes: {
   remote-1: "mfe-app-1@https://localhost:3001/remoteEntry.js" // ? URL Pattern: "<app-name>@<app-url>/remoteEntry.js"
  },
}),        

  • You can add the list of app URLs mapping to their remoteEntry.js to configure the components which are to be consumed as remote Micro Frontends.
  • Load the list of configurations into the "remotes" property of Module Federation Plugin. This property can take multiple Remote Entries and can host multiple app URLs.

  1. Declare the remote components as modules of your application

  • The consumed remote components should be declared as Modules to use them in the Host Application.
  • Create a file named remoteTypes.d.ts in /src folder of the host application.


///<reference types="react" />

type Props = {
    activeTabId: string;
}; // ? Define the Props as per the component's definition.

declare module "remote-1/CounterAppOne" {
    const CounterAppOne: React.ComponentType<Props>; // ? Add props as per the component (if needed).
    export default CounterAppOne;
}
declare module "remote-1/CounterAppTwo" {
    const CounterAppTwo: React.ComponentType; // ? Add props as per the component (if needed).
    export default CounterAppTwo;
}        

  • Add all the remote Micro Frontend Modules and also define their input attributes as per the requirement.

  1. Import the remote module like a regular React Component when needed

  • Lazy Loading the modules is also supported and recommended as these are 'Run-Time' rendered components.


import React from "react";

const CounterAppOne = React.lazy(() => import("amzn/CounterAppOne"));
const CounterAppTwo = React.lazy(() => import("amzn/CounterAppTwo"));

<Suspense fallback={<Spinner size='large' />}>
    <CounterAppOne activeTabId={'tab-id-1'} />
</Suspense>
<Suspense fallback={<Spinner size='large' />}>
    <CounterAppTwo />
</Suspense>        

  • <Suspense></> lets components “wait” for something before rendering. It helps the app in loading components dynamically with React.lazy.
  • More: React Suspense API – React
  • Lazy Loading the remote entry module is completely recommended as the remote payload fetch might take time.
  • The host application will fetch the remoteEntry.js file similar to the way any other API call. Since the download would take some time, using Lazy Load and adding a fallback option is very necessary.

  1. Update index.tsx and create new bootstrap.tsx

  • Since the component added should be lazily loaded, proper app initiation time is needed.
  • Adding a boostrap.tsx and loading the app from that will be needed for this type of lazy loading.
  • Create a file boostrap.tsx parallel to index.tsx, transfer the entire code of index.tsx to boostrap.tsx. Fill index.tsx with the following:


import('./bootstrap');

export default {};        

  • Once the configuration is done, the lazy loaded component should load in the hosted screen, as shown below:

Container app showing MFE components
Container app displaying shared components from APP-1 & APP-2

Best Practices to Deploy Micro Frontend

Can any small piece become a Micro Frontend?

is this MFE meme
not every small isolated piece of code is MFE.

No! Following a set of rules is always needed for better results.

Since Micro Frontend is a new implementation to the existing Monolithic SPA Web apps, following some Design Patterns and best practices while development would help in better implementation.

The following are some:

Styling and CSS scopes isolation – CSS modules to the rescue

  • Shared dependencies would be downloaded along with the remoteEntry.js file and will get applied to the MFE components when used in a regular way.
  • If there’s a need to apply an additional layer of styles to the remote components, following the regular approach of stylesheets would work.
  • Avoid clashing the CSS scopes and class names. A common class name between the provider and the host applications would lead to a mix in the styles applied.
  • CSS modules come to the rescue here and they effectively assign random class names to CSS classes for each individual component.

Shared Redux store – Requires code sharing, so do not use it

  • A Shared Redux store requires code sharing and can also result in irregular data values. Redux can be avoided from the micro frontend module as the components would be calling APIs to fetch real-time data.
  • If having redux is a mandate for the application, let each micro frontend have its own Redux store.

Cross-app communication

  • Caching and Cookies would be an effective way to communicate between provider and host apps.
  • Browser Storages like Local, Session, and Cache Storages would help in cross-app communications.

Remote entries are down – Error Boundaries

  • The host app would fail to display the MFE component when the remote entries provided by the Provider App or the Entire Provider App are down.
  • Error Boundaries effectively protect us in such cases, allowing us to implement some fallback components to be shown when the remote component is unavailable.

Session management and authentication – Secure HTTP-only cookies

  • This is the responsibility of the host application. Opting for secure HTTP cookies requested by the host application would be the right approach.
  • The host app generates its own HTTP Auth Values, all the mounted microservices and their components use these cookies to communicate with the backend API microservices.

Caching – Unique imported remote entry URL

  • Since we import remote components via static URL with remoteEntry.js, that might cause spam.
  • On the deployment of a new version of a micro frontend, the old cache version might be loaded by a web browser. So, make sure to add some random string to the imported URL.

Metrics & Alarms - Deploying Logs and Alarms

  • As the app would be using multiple own components and various shared entries. Keeping track of every granular would become more tedious.
  • Adding logs and metrics which could record the failure of a shared remote entry or improper data sharing with the remote entry will let the developers keep a track of MFE failures.


Summary

isolate things meme
MFE isolates

Isolating use cases according to the features would definitely help teams work independently and efficiently. Scaling features, Managing development teams, Load balancing, and Handling change requests would become an easy part of the development process.

Microfrontends introduced a replica of Microservices into UI, is still a growing adaption in the JS World. Webapps built, controlled, and bootstrapped implementing different trending frameworks like Angular, React, Vue, Nuxt, Tweenmax, and others would eventually fall back to the complied JS code while being rendered to the browser. This gives a good scope to Microfrontnds as a part of the new age Webtech adaption and will eventually become the prime architectural requirement.

Code Repo Reference: https://github.com/PavanAditya/Microfrontend-ModuleFederation-React-Lerna


Follow Me at:

Portfolio: https://pavanaditya.com

GitHub: https://github.com/PavanAditya

Facebook: Pavan Aditya M S

要查看或添加评论,请登录

Pavan Aditya M S的更多文章

  • Theory of Micro Frontends

    Theory of Micro Frontends

    Share your Code. Sharing is Caring :) Contents: Microfrontends Definition Why Microfrontends Micro Frontend Reality…

    1 条评论

社区洞察

其他会员也浏览了