Revolutionizing Frontend Development: Unleashing the Might of Micro Frontends

Santheepkumar

Santheepkumar / June 13, 2023

7 min read––– views

Little Intro

In the ever-evolving landscape of web development, the concept of micro frontends has emerged as a groundbreaking architectural pattern that promises greater flexibility, scalability, and collaboration. By breaking down monolithic frontend applications into smaller, self-contained modules, micro frontends enable developers to embrace a modular approach, empowering teams to work independently and deliver highly cohesive user experiences. In this article, we will dive deep into the world of micro frontends, explore their benefits, and demonstrate their implementation using React.

Understanding Micro Frontends

Micro frontends, inspired by the concept of microservices in backend development, advocate for the decomposition of frontend applications into smaller, manageable units. In this architecture, each module, known as a micro frontend, encapsulates a specific feature or functionality of the application. These micro frontends can be developed, deployed, and maintained independently, utilizing different technologies and frameworks.

Unlike traditional monolithic applications, micro frontends are designed to communicate and interact with each other, forming a cohesive user experience. This communication is typically established through well-defined APIs, events, or shared state management. By decoupling frontend modules, micro frontends enable teams to work autonomously, promoting faster iteration, efficient development cycles, and easier maintenance.

Benefits of Micro Frontends

1. Independent Development and Deployment

Micro frontends liberate development teams from the constraints of a monolithic codebase. Each micro frontend represents a separate codebase that can be developed and deployed independently. This independence allows teams to work at their own pace, using the technologies, frameworks, and programming languages of their choice. Different teams can focus on specific micro frontends without being blocked by others, resulting in accelerated development and increased productivity.

2. Scalability and Performance Optimization

With micro frontends, horizontal scalability becomes achievable. Each micro frontend can be deployed and scaled independently based on its specific requirements. This modular architecture enables teams to optimize the performance of individual modules without affecting the entire application. Additionally, micro frontends can be loaded asynchronously, leading to faster initial load times and enhanced user experience.

3. Flexibility and Technology Diversity

Micro frontends provide the flexibility to choose the most suitable technology stack for each module. Different micro frontends can utilize different frameworks, libraries, or programming languages based on their unique needs. This flexibility fosters innovation, allows teams to experiment with new technologies, and enables them to leverage the strengths of each tool without compromising the overall application architecture.

4. Easy Maintenance and Upgrades

Maintaining and upgrading a large frontend application can be a daunting task. Micro frontends offer a solution to this challenge by breaking down the application into smaller, more manageable units. Since each micro frontend is self-contained, maintenance and upgrades can be performed independently, reducing the risk of introducing regressions and facilitating smoother releases and rollbacks.

5. Team Collaboration and Autonomy

Micro frontends promote collaboration among multiple teams, each responsible for developing and maintaining specific modules. Teams can work independently, making decisions regarding technology choices, development processes, and deployment strategies without interfering with others. This autonomy boosts team morale, encourages ownership, and fosters a culture of innovation and continuous improvement.

Implementing Micro Frontends with React

React, a popular JavaScript library for building user interfaces, is well-suited for implementing micro frontends due to its component-based architecture. Here's an example that demonstrates how React can be used in a micro frontend setup:

Micro Frontend A - React App with Header Component

import React from 'react';

const Header: React.FC = (): JSX.Element => {
  return <div className="p-10 bg-gray-400 m-10 rounded-md">My Header</div>;
};

export default Header;

Micro Frontend A - Webpack Config

const HtmlWebPackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

const deps = require('./package.json').dependencies;
module.exports = (_, argv) => ({
  output: {
    publicPath: 'http://localhost:3001/'
  },

  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js', '.json']
  },

  devServer: {
    port: 3001,
    historyApiFallback: true
  },

  module: {
    rules: [
      {
        test: /\.m?js/,
        type: 'javascript/auto',
        resolve: {
          fullySpecified: false
        }
      },
      {
        test: /\.(css|s[ac]ss)$/i,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      },
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  },

  plugins: [
    new ModuleFederationPlugin({
      name: 'header',
      filename: 'remoteEntry.js',
      remotes: {},
      exposes: {
        './Header': './src/Header.tsx'
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react
        },
        'react-dom': {
          singleton: true,
          requiredVersion: deps['react-dom']
        }
      }
    }),
    new HtmlWebPackPlugin({
      template: './src/index.html'
    })
  ]
});
import React from 'react';

const Footer: React.FC = (): JSX.Element => {
  return <div className="p-10 bg-gray-400 m-10 rounded-md">My Footer</div>;
};

export default Footer;

Micro Frontend B - Webpack Config

const HtmlWebPackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

const deps = require('./package.json').dependencies;
module.exports = (_, argv) => ({
  output: {
    publicPath: 'http://localhost:3002/'
  },

  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js', '.json']
  },

  devServer: {
    port: 3002,
    historyApiFallback: true
  },

  module: {
    rules: [
      {
        test: /\.m?js/,
        type: 'javascript/auto',
        resolve: {
          fullySpecified: false
        }
      },
      {
        test: /\.(css|s[ac]ss)$/i,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      },
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  },

  plugins: [
    new ModuleFederationPlugin({
      name: 'footer',
      filename: 'remoteEntry.js',
      remotes: {},
      exposes: {
        './Footer': './src/Footer.tsx'
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react
        },
        'react-dom': {
          singleton: true,
          requiredVersion: deps['react-dom']
        }
      }
    }),
    new HtmlWebPackPlugin({
      template: './src/index.html'
    })
  ]
});
import React from 'react';
import ReactDOM from 'react-dom';

import './index.scss';
// Micro Frontend A
import Header from 'header/Header';
// Micro Frontend B
import Footer from 'footer/Footer';

const App = () => (
  <div className="mt-10 text-3xl mx-auto max-w-6xl">
    <Header />
    <div>My App</div>
    <Footer />
  </div>
);
ReactDOM.render(<App />, document.getElementById('app'));

Main Application - Webpack Config

const HtmlWebPackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

const deps = require('./package.json').dependencies;
module.exports = (_, argv) => ({
  output: {
    publicPath: 'http://localhost:3003/'
  },

  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js', '.json']
  },

  devServer: {
    port: 3003,
    historyApiFallback: true
  },

  module: {
    rules: [
      {
        test: /\.m?js/,
        type: 'javascript/auto',
        resolve: {
          fullySpecified: false
        }
      },
      {
        test: /\.(css|s[ac]ss)$/i,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      },
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      }
    ]
  },

  plugins: [
    new ModuleFederationPlugin({
      name: 'home',
      filename: 'remoteEntry.js',
      remotes: {
        // Micro Frontend A
        header: 'header@http://localhost:3001/remoteEntry.js',
        // Micro Frontend B
        footer: 'header@http://localhost:3002/remoteEntry.js'
      },
      exposes: {}
    }),
    new HtmlWebPackPlugin({
      template: './src/index.html'
    })
  ]
});

In this example, we have a main application component (MainApplication) that integrates two micro frontends (MicroFrontendA and MicroFrontendB) built with React. Each micro frontend is developed as a separate React component, encapsulating its specific functionality and user interface.

The main application component acts as a composition root, rendering the micro frontends alongside other components. By breaking down the application into smaller, reusable components, React enables teams to develop and maintain each micro frontend independently.

Conclusion

Micro frontends offer a revolutionary approach to frontend development, enabling teams to break free from monolithic applications and embrace modular architectures. By decomposing the application into smaller, self-contained units, micro frontends unlock the potential for independent development, scalability, flexibility, and enhanced collaboration. With the power of React, developers can easily implement and integrate micro frontends, leveraging the component-based nature of the library.

While micro frontends bring numerous benefits, they also require careful consideration of communication strategies, routing mechanisms, shared dependencies, and testing approaches. However, the advantages gained in terms of development autonomy, scalability, and maintenance ease make micro frontends a compelling choice for building modern, complex frontend applications.

So, embrace the modular revolution, explore the possibilities of micro frontends, and unlock the true potential of frontend development with React!

Subscribe to the newsletter

Get emails from me about web development, tech, and early access to new articles.

- subscribers – 32 issues